diff --git a/eth-bytecode-db/Cargo.lock b/eth-bytecode-db/Cargo.lock index e516a937e..58dbb2724 100644 --- a/eth-bytecode-db/Cargo.lock +++ b/eth-bytecode-db/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -1187,9 +1187,9 @@ dependencies = [ [[package]] name = "blockscout-service-launcher" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a63d6b6e01527cefc2c82f2ef1b874817d4d6cb51f9bacffd116a94917387dc6" +checksum = "98faf66096af3a77362da42c2861e59427187b8f1687f482cb4d04465176d3d0" dependencies = [ "actix-cors", "actix-web", @@ -2130,9 +2130,9 @@ dependencies = [ "tracing", "tracing-subscriber", "url", - "verification-common", - "verifier-alliance-entity", - "verifier-alliance-migration", + "verification-common 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=3892914)", + "verifier-alliance-entity 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=ec1c755)", + "verifier-alliance-migration 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=ec1c755)", ] [[package]] @@ -2195,8 +2195,8 @@ dependencies = [ "tonic", "tracing", "url", - "verifier-alliance-entity", - "verifier-alliance-migration", + "verifier-alliance-entity 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=ec1c755)", + "verifier-alliance-migration 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=ec1c755)", ] [[package]] @@ -5152,6 +5152,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "readonly" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -7629,6 +7640,22 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "verification-common" +version = "0.1.0" +source = "git+https://github.com/blockscout/blockscout-rs?rev=1164e09#1164e093cb45afd9b9445428d178f759c1e0ab74" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "anyhow", + "blockscout-display-bytes", + "bytes", + "readonly", + "serde", + "serde_json", + "serde_with 3.11.0", +] + [[package]] name = "verification-common" version = "0.1.0" @@ -7644,9 +7671,39 @@ dependencies = [ "serde_with 3.11.0", ] +[[package]] +name = "verifier-alliance-database" +version = "0.1.0" +dependencies = [ + "anyhow", + "blockscout-display-bytes", + "blockscout-service-launcher", + "keccak-hash 0.11.0", + "pretty_assertions", + "sea-orm", + "serde", + "serde_json", + "serde_with 3.11.0", + "sha2", + "sha3", + "strum", + "tokio", + "verification-common 0.1.0 (git+https://github.com/blockscout/blockscout-rs?rev=1164e09)", + "verifier-alliance-entity 0.1.0", + "verifier-alliance-migration 0.1.0", +] + +[[package]] +name = "verifier-alliance-entity" +version = "0.1.0" +dependencies = [ + "sea-orm", +] + [[package]] name = "verifier-alliance-entity" version = "0.1.0" +source = "git+https://github.com/blockscout/blockscout-rs?rev=ec1c755#ec1c7554fde2b67350fc44e905040698a8cdf40b" dependencies = [ "sea-orm", ] @@ -7659,6 +7716,15 @@ dependencies = [ "sea-orm-migration", ] +[[package]] +name = "verifier-alliance-migration" +version = "0.1.0" +source = "git+https://github.com/blockscout/blockscout-rs?rev=ec1c755#ec1c7554fde2b67350fc44e905040698a8cdf40b" +dependencies = [ + "async-std", + "sea-orm-migration", +] + [[package]] name = "version_check" version = "0.9.5" diff --git a/eth-bytecode-db/Cargo.toml b/eth-bytecode-db/Cargo.toml index 97e9c5991..72a63f7ff 100644 --- a/eth-bytecode-db/Cargo.toml +++ b/eth-bytecode-db/Cargo.toml @@ -8,6 +8,7 @@ members = [ "eth-bytecode-db/migration", "eth-bytecode-db/verifier-alliance-entity", "eth-bytecode-db/verifier-alliance-migration", + "verifier-alliance-database", ] [workspace.dependencies] @@ -16,8 +17,13 @@ eth-bytecode-db = { path = "eth-bytecode-db" } eth-bytecode-db-proto = { path = "eth-bytecode-db-proto" } eth-bytecode-db-server = { path = "eth-bytecode-db-server" } migration = { path = "eth-bytecode-db/migration" } -verifier-alliance-entity = { path = "eth-bytecode-db/verifier-alliance-entity" } -verifier-alliance-migration = { path = "eth-bytecode-db/verifier-alliance-migration" } +verifier-alliance-entity = { git = "https://github.com/blockscout/blockscout-rs", rev = "ec1c755" } +verifier-alliance-database = { path = "verifier-alliance-database" } +verifier-alliance-migration = { git = "https://github.com/blockscout/blockscout-rs", rev = "ec1c755" } + +verifier-alliance-entity-v1 = { path = "eth-bytecode-db/verifier-alliance-entity", package = "verifier-alliance-entity" } +verifier-alliance-migration-v1 = { path = "eth-bytecode-db/verifier-alliance-migration", package = "verifier-alliance-migration" } +verification-common-v1 = { git = "https://github.com/blockscout/blockscout-rs", rev = "1164e09", package = "verification-common" } actix-prost = { git = "https://github.com/blockscout/actix-prost", rev = "4cbba2a" } actix-prost-macros = { git = "https://github.com/blockscout/actix-prost", rev = "4cbba2a" } @@ -29,7 +35,7 @@ anyhow = { version = "1" } async-std = { version = "^1" } async-trait = { version = "0.1" } blockscout-display-bytes = { version = "1.1.0" } -blockscout-service-launcher = { version = "0.14.0", features = ["database-1_0"] } +blockscout-service-launcher = { version = "0.15.0", default-features = false, features = ["database-1_0"] } bytes = { version = "1.2" } ethabi = { version = "18.0" } ethers = { version = "2.0.0" } @@ -56,9 +62,12 @@ semver = { version = "1.0" } serde = { version = "1" } serde_json = { version = "1.0" } serde_with = { version = "3.11.0" } +sha2 = { version = "0.10.8" } +sha3 = { version = "0.10.8" } smart-contract-verifier-proto = { git = "https://github.com/blockscout/blockscout-rs", rev = "7a6e9400" } solidity-metadata = { version = "1.0" } sourcify = { git = "https://github.com/blockscout/blockscout-rs", rev = "457af68" } +strum = { version = "0.26.3", default-features = false, features = ["derive"] } thiserror = { version = "1" } tokio = { version = "1" } tokio-stream = { version = "0.1" } diff --git a/eth-bytecode-db/eth-bytecode-db-server/Cargo.toml b/eth-bytecode-db/eth-bytecode-db-server/Cargo.toml index 22113fa30..774a39ccc 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/Cargo.toml +++ b/eth-bytecode-db/eth-bytecode-db-server/Cargo.toml @@ -10,7 +10,7 @@ amplify = { workspace = true } anyhow = { workspace = true } async-trait = { workspace = true } blockscout-display-bytes = { workspace = true } -blockscout-service-launcher = { workspace = true } +blockscout-service-launcher = { workspace = true, features = ["launcher", "tracing"] } eth-bytecode-db = { workspace = true } eth-bytecode-db-proto = { workspace = true } ethers = { workspace = true, features = ["solc"] } diff --git a/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/verifier_alliance_setup.rs b/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/verifier_alliance_setup.rs index a116827b8..68093e8f0 100644 --- a/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/verifier_alliance_setup.rs +++ b/eth-bytecode-db/eth-bytecode-db-server/tests/verification_test_helpers/verifier_alliance_setup.rs @@ -64,7 +64,7 @@ impl<'a, Request> From<&'a Request> for RequestWrapper<'a, Request> { } } -impl<'a, Request> RequestWrapper<'a, Request> { +impl RequestWrapper<'_, Request> { pub fn header(&mut self, key: &str, value: &str) { let key = reqwest::header::HeaderName::from_str(key) .expect("Error converting key string into header name"); diff --git a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs index 75cd2d891..959d990c0 100644 --- a/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs +++ b/eth-bytecode-db/eth-bytecode-db/src/verification/handlers/mod.rs @@ -167,7 +167,7 @@ impl<'a> VerifierAllianceDbAction<'a> { } } -impl<'a> VerifierAllianceDbAction<'a> { +impl VerifierAllianceDbAction<'_> { fn contract_address(&self) -> Option { match self { VerifierAllianceDbAction::IgnoreDb => None, diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/code.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/code.rs index 5ebe04666..0517d6abc 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/code.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/code.rs @@ -11,6 +11,12 @@ pub struct Model { column_type = "VarBinary(StringLen::None)" )] pub code_hash: Vec, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, + pub created_by: String, + pub updated_by: String, + #[sea_orm(column_type = "VarBinary(StringLen::None)")] + pub code_hash_keccak: Vec, #[sea_orm(column_type = "VarBinary(StringLen::None)", nullable)] pub code: Option>, } diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts.rs index bc1cfa474..ea5266ab1 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts.rs @@ -17,8 +17,6 @@ pub struct Model { pub name: String, pub fully_qualified_name: String, #[sea_orm(column_type = "JsonBinary")] - pub sources: Json, - #[sea_orm(column_type = "JsonBinary")] pub compiler_settings: Json, #[sea_orm(column_type = "JsonBinary")] pub compilation_artifacts: Json, @@ -50,10 +48,18 @@ pub enum Relation { on_delete = "NoAction" )] Code1, + #[sea_orm(has_many = "super::compiled_contracts_sources::Entity")] + CompiledContractsSources, #[sea_orm(has_many = "super::verified_contracts::Entity")] VerifiedContracts, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::CompiledContractsSources.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::VerifiedContracts.def() diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts_sources.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts_sources.rs new file mode 100644 index 000000000..b6d4c7d23 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/compiled_contracts_sources.rs @@ -0,0 +1,48 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "compiled_contracts_sources")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub compilation_id: Uuid, + #[sea_orm(column_type = "VarBinary(StringLen::None)")] + pub source_hash: Vec, + pub path: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::compiled_contracts::Entity", + from = "Column::CompilationId", + to = "super::compiled_contracts::Column::Id", + on_update = "NoAction", + on_delete = "NoAction" + )] + CompiledContracts, + #[sea_orm( + belongs_to = "super::sources::Entity", + from = "Column::SourceHash", + to = "super::sources::Column::SourceHash", + on_update = "NoAction", + on_delete = "NoAction" + )] + Sources, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CompiledContracts.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Sources.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contract_deployments.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contract_deployments.rs index f2f560af1..18f0e68c1 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contract_deployments.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contract_deployments.rs @@ -7,6 +7,10 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, + pub created_by: String, + pub updated_by: String, pub chain_id: Decimal, #[sea_orm(column_type = "VarBinary(StringLen::None)")] pub address: Vec, diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contracts.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contracts.rs index 03604ca39..1df95235f 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contracts.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/contracts.rs @@ -7,6 +7,10 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, + pub created_by: String, + pub updated_by: String, #[sea_orm(column_type = "VarBinary(StringLen::None)")] pub creation_code_hash: Vec, #[sea_orm(column_type = "VarBinary(StringLen::None)")] diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/lib.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/lib.rs index deab4d6ff..5875016d7 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/lib.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/lib.rs @@ -4,6 +4,8 @@ pub mod prelude; pub mod code; pub mod compiled_contracts; +pub mod compiled_contracts_sources; pub mod contract_deployments; pub mod contracts; +pub mod sources; pub mod verified_contracts; diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/prelude.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/prelude.rs index 766bbb1e7..45df3bfd1 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/prelude.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/prelude.rs @@ -2,6 +2,7 @@ pub use super::{ code::Entity as Code, compiled_contracts::Entity as CompiledContracts, + compiled_contracts_sources::Entity as CompiledContractsSources, contract_deployments::Entity as ContractDeployments, contracts::Entity as Contracts, - verified_contracts::Entity as VerifiedContracts, + sources::Entity as Sources, verified_contracts::Entity as VerifiedContracts, }; diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/sources.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/sources.rs new file mode 100644 index 000000000..7f4fb3fb8 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/sources.rs @@ -0,0 +1,35 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "sources")] +pub struct Model { + #[sea_orm( + primary_key, + auto_increment = false, + column_type = "VarBinary(StringLen::None)" + )] + pub source_hash: Vec, + #[sea_orm(column_type = "VarBinary(StringLen::None)")] + pub source_hash_keccak: Vec, + pub content: String, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, + pub created_by: String, + pub updated_by: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::compiled_contracts_sources::Entity")] + CompiledContractsSources, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CompiledContractsSources.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/verified_contracts.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/verified_contracts.rs index b8d21be6c..e7fed8da5 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/verified_contracts.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-entity/src/verified_contracts.rs @@ -18,11 +18,13 @@ pub struct Model { pub creation_values: Option, #[sea_orm(column_type = "JsonBinary", nullable)] pub creation_transformations: Option, + pub creation_metadata_match: Option, pub runtime_match: bool, #[sea_orm(column_type = "JsonBinary", nullable)] pub runtime_values: Option, #[sea_orm(column_type = "JsonBinary", nullable)] pub runtime_transformations: Option, + pub runtime_metadata_match: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/lib.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/lib.rs index 6d1b3f91e..b43fff285 100644 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/lib.rs +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/lib.rs @@ -1,34 +1,12 @@ pub use sea_orm_migration::prelude::*; -use sea_orm_migration::sea_orm::{Statement, TransactionTrait}; -mod m20220101_000001_initial_migration; +mod m20241028_143125_initialize_schema_v1; pub struct Migrator; #[async_trait::async_trait] impl MigratorTrait for Migrator { fn migrations() -> Vec> { - vec![Box::new(m20220101_000001_initial_migration::Migration)] + vec![Box::new(m20241028_143125_initialize_schema_v1::Migration)] } } - -pub async fn from_sql(manager: &SchemaManager<'_>, content: &str) -> Result<(), DbErr> { - exec_stmts(manager, content.split(';')).await -} - -pub async fn exec_stmts>( - manager: &SchemaManager<'_>, - stmts: impl IntoIterator, -) -> Result<(), DbErr> { - let txn = manager.get_connection().begin().await?; - for st in stmts { - let st = Into::::into(st); - txn.execute(Statement::from_string( - manager.get_database_backend(), - st.clone(), - )) - .await - .map_err(|e| DbErr::Migration(format!("{e}\nQuery: {st}")))?; - } - txn.commit().await -} diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20220101_000001_initial_migration.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20220101_000001_initial_migration.rs deleted file mode 100644 index 417c2f44b..000000000 --- a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20220101_000001_initial_migration.rs +++ /dev/null @@ -1,433 +0,0 @@ -use sea_orm_migration::prelude::*; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let statements = get_table_definitions() - .into_iter() - .chain(get_timestamp_triggers()) - .chain(get_ownership_triggers()); - crate::exec_stmts(manager, statements).await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let statements = drop_table_definitions() - .into_iter() - .chain(drop_timestamp_triggers()) - .chain(drop_ownership_triggers()); - crate::exec_stmts(manager, statements).await - } -} - -fn get_table_definitions() -> Vec { - let sql = r#" - /* Needed for gen_random_uuid() */ - CREATE EXTENSION pgcrypto; - - /* - The `code` table stores a mapping from code hash to bytecode. This table may store - both normalized and unnormalized code. - - Code is normalized when all libraries/immutable variables that are not constants are - replaced with zeroes. In other words the variable `address private immutable FACTORY = 0xAABB...EEFF` - would not be replaced with zeroes, but the variable `address private immutable OWNER = msg.sender` would. - - The `code` column is not marked NOT NULL because we need to distinguish between - empty code, and no code. Empty code occurs when a contract is deployed with no runtime code. - No code occurs when a contract's code is written directly to the chain in a hard fork - */ - CREATE TABLE code - ( - /* the keccak256 hash of the `code` column */ - code_hash bytea NOT NULL PRIMARY KEY, - - /* the bytecode */ - code bytea - ); - - /* ensure the sentinel value exists */ - INSERT INTO code (code_hash, code) VALUES ('\x', NULL); - - /* - The `contracts` table stores information which can be used to identify a unique contract in a - chain-agnostic manner. In other words, suppose you deploy the same contract on two chains, all - properties that would be shared across the two chains should go in this table because they uniquely - identify the contract. - */ - CREATE TABLE contracts - ( - /* an opaque id */ - id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), - - /* - the creation code is the calldata (for eoa creations) or the instruction input (for create/create2) - the runtime code is the bytecode that's returned by the creation code and stored on-chain - - neither fields are normalized - */ - creation_code_hash bytea NOT NULL REFERENCES code (code_hash), - runtime_code_hash bytea NOT NULL REFERENCES code (code_hash), - - CONSTRAINT contracts_pseudo_pkey UNIQUE (creation_code_hash, runtime_code_hash) - ); - - CREATE INDEX contracts_creation_code_hash ON contracts USING btree(creation_code_hash); - CREATE INDEX contracts_runtime_code_hash ON contracts USING btree(runtime_code_hash); - CREATE INDEX contracts_creation_code_hash_runtime_code_hash ON contracts USING btree(creation_code_hash, runtime_code_hash); - - /* - The `contract_deployments` table stores information about a specific deployment unique to a chain. - One contract address may have multiple deployments on a single chain if SELFDESTRUCT/CREATE2 is used - The info stored in this table should be retrievable from an archive node. In other words, it should - not be augmented with any inferred data - */ - CREATE TABLE contract_deployments - ( - /* an opaque id*/ - id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), - - /* - these three fields uniquely identify a specific deployment of a contract, assuming - that it is impossible to deploy to successfully an address twice in the same transaction - (create2 -> selfdestruct -> create2 should revert on the second create2) - - in the case of a "genesis" contract, the transaction_hash should be set - to keccak256(creation_code_hash || runtime_code_hash). this is because the transaction_hash - needs to differ to distinguish between two versions of the same genesis contract, and so - it needs to embed inside it the only feature that changes. - - also note that for genesis contracts, creation_code_hash may be '\x' (i.e. there is no creation code) - */ - chain_id numeric NOT NULL, - address bytea NOT NULL, - transaction_hash bytea NOT NULL, - - /* - geth full nodes have the ability to prune the transaction index, so if the transaction_hash - can't be found directly, use the block_number and transaction_index. make sure to compare the transaction_hash to - make sure it matches! - - for genesis contracts, both values should be set to -1 - */ - block_number numeric NOT NULL, - transaction_index numeric NOT NULL, - - /* - this is the address which actually deployed the contract (i.e. called the create/create2 opcode) - */ - deployer bytea NOT NULL, - - /* the contract itself */ - contract_id uuid NOT NULL REFERENCES contracts(id), - - CONSTRAINT contract_deployments_pseudo_pkey UNIQUE (chain_id, address, transaction_hash) - ); - - CREATE INDEX contract_deployments_contract_id ON contract_deployments USING btree(contract_id); - - /* - The `compiled_contracts` table stores information about a specific compilation. A compilation is - defined as a set of inputs (compiler settings, source code, etc) which uniquely correspond to a - set of outputs (bytecode, documentation, ast, etc) - */ - CREATE TABLE compiled_contracts - ( - /* an opaque id */ - id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), - - /* timestamps */ - created_at timestamptz NOT NULL DEFAULT NOW(), - updated_at timestamptz NOT NULL DEFAULT NOW(), - - /* ownership */ - created_by varchar NOT NULL DEFAULT (current_user), - updated_by varchar NOT NULL DEFAULT (current_user), - - /* - these three fields uniquely identify the high-level compiler mode to use - - note that the compiler is the software ('solc', 'vyper', 'huff') while language is - the syntax ('solidity', 'vyper', 'yul'). there may be future compilers which aren't solc - but can still compile solidity, which is why we need to differentiate the two - - the version should uniquely identify the compiler - */ - compiler VARCHAR NOT NULL, - version VARCHAR NOT NULL, - language VARCHAR NOT NULL, - - /* - the name is arbitrary and often not a factor in verifying contracts (solidity encodes it in - the auxdata which we ignore, and vyper doesn't even have the concept of sourceunit-level names) - because of this we don't include it in the unique constraint. it is stored purely for informational - purposes - */ - name VARCHAR NOT NULL, - - /* the fully qualified name is compiler-specific and indicates exactly which contract to look for */ - fully_qualified_name VARCHAR NOT NULL, - - /* map of path to source code (string => string) */ - sources jsonb NOT NULL, - - /* compiler-specific settings such as optimization, linking, etc (string => any) */ - compiler_settings jsonb NOT NULL, - - /* general and compiler-specific artifacts (abi, userdoc, devdoc, licenses, etc) */ - compilation_artifacts jsonb NOT NULL, - - /* - note that we can't pull out creation/runtime code into its own table - imagine that a future compiler and language combo result in the same bytecode - this is something that we would want a record of, because the two sources are semantically - unique - in other words, the hypothetical table would need to be keyed on everything that this table already is - */ - - /* these fields store info about the creation code (sourcemaps, linkreferences) */ - creation_code_hash bytea NOT NULL REFERENCES code (code_hash), - creation_code_artifacts jsonb NOT NULL, - - /* - these fields store info about the runtime code (sourcemaps, linkreferences, immutables) - the runtime code should be normalized (i.e. immutables set to zero) - */ - runtime_code_hash bytea NOT NULL REFERENCES code (code_hash), - runtime_code_artifacts jsonb NOT NULL, - - /* - two different compilers producing the same bytecode is unique enough that we want to preserve it - the same compiler with two different versions producing the same bytecode is not unique (f.ex nightlies) - */ - CONSTRAINT compiled_contracts_pseudo_pkey UNIQUE (compiler, language, creation_code_hash, runtime_code_hash) - ); - - CREATE INDEX compiled_contracts_creation_code_hash ON compiled_contracts USING btree (creation_code_hash); - CREATE INDEX compiled_contracts_runtime_code_hash ON compiled_contracts USING btree (runtime_code_hash); - - /* - The verified_contracts table links an on-chain contract with a compiled_contract - Note that only one of creation or runtime bytecode must match, because: - We could get a creation match but runtime mismatch if the contract is a proxy that uses assembly to return custom runtime bytecode - We could get a runtime match but creation mismatch if the contract is deployed via a create2 factory - */ - CREATE TABLE verified_contracts - ( - /* an opaque id, but sequentially ordered */ - id BIGSERIAL NOT NULL PRIMARY KEY, - - /* timestamps */ - created_at timestamptz NOT NULL DEFAULT NOW(), - updated_at timestamptz NOT NULL DEFAULT NOW(), - - /* ownership */ - created_by varchar NOT NULL DEFAULT (current_user), - updated_by varchar NOT NULL DEFAULT (current_user), - - /* the specific deployment and the specific compilation */ - deployment_id uuid NOT NULL REFERENCES contract_deployments (id), - compilation_id uuid NOT NULL REFERENCES compiled_contracts (id), - - /* - if the code matches, then the values and transformation fields contain - all the information required to transform the compiled bytecode to the deployed bytecode - see the json schemas provided for more information - */ - - creation_match bool NOT NULL, - creation_values jsonb, - creation_transformations jsonb, - - runtime_match bool NOT NULL, - runtime_values jsonb, - runtime_transformations jsonb, - - CONSTRAINT verified_contracts_pseudo_pkey UNIQUE (compilation_id, deployment_id) - ); - - CREATE INDEX verified_contracts_deployment_id ON verified_contracts USING btree (deployment_id); - CREATE INDEX verified_contracts_compilation_id ON verified_contracts USING btree (compilation_id); - "#; - sql.split(';').map(Into::into).collect() -} - -fn drop_table_definitions() -> Vec { - let sql = r#" - DROP TABLE "verified_contracts"; - DROP TABLE "compiled_contracts"; - DROP TABLE "contract_deployments"; - DROP TABLE "contracts"; - DROP TABLE "code"; - - DROP EXTENSION "pgcrypto"; - "#; - sql.split(';').map(Into::into).collect() -} - -fn get_timestamp_triggers() -> Vec { - let statements = vec![ - r#" - /* Needed to automatically set `created_at` fields on insertions. */ - CREATE FUNCTION trigger_set_created_at() - RETURNS TRIGGER AS $$ - BEGIN - NEW.created_at = NOW(); - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - /* Needed to prevent modifying `crerated_at` fields on updates */ - CREATE FUNCTION trigger_reuse_created_at() - RETURNS TRIGGER AS - $$ - BEGIN - NEW.created_at = OLD.created_at; - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - /* Needed to automatically set `updated_at` fields on insertions and updates */ - CREATE FUNCTION trigger_set_updated_at() - RETURNS TRIGGER AS $$ - BEGIN - NEW.updated_by = NOW(); - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - DO - $$ - DECLARE - t_name text; - BEGIN - FOR t_name IN (VALUES ('compiled_contracts'), - ('verified_contracts')) - LOOP - EXECUTE format('CREATE TRIGGER insert_set_created_at - BEFORE INSERT ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_created_at()', - t_name); - - EXECUTE format('CREATE TRIGGER insert_set_updated_at - BEFORE INSERT ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_updated_at()', - t_name); - - EXECUTE format('CREATE TRIGGER update_reuse_created_at - BEFORE UPDATE ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_reuse_created_at()', - t_name); - - EXECUTE format('CREATE TRIGGER update_set_updated_at - BEFORE UPDATE ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_updated_at()', - t_name); - END LOOP; - END; - $$ LANGUAGE plpgsql; - "#, - ]; - statements.into_iter().map(Into::into).collect() -} - -fn drop_timestamp_triggers() -> Vec { - let sql = r#" - DROP FUNCTION trigger_set_created_at; - DROP FUNCTION trigger_reuse_created_at; - DROP FUNCTION trigger_set_updated_at; - "#; - sql.split(';').map(Into::into).collect() -} - -fn get_ownership_triggers() -> Vec { - let statements = vec![ - r#" - /* Needed to automatically set `created_by` fields on insertions. */ - CREATE FUNCTION trigger_set_created_by() - RETURNS TRIGGER AS $$ - BEGIN - NEW.created_by = current_user; - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - /* Needed to prevent modifying `crerated_by` fields on updates */ - CREATE FUNCTION trigger_reuse_created_by() - RETURNS TRIGGER AS - $$ - BEGIN - NEW.created_by = OLD.created_by; - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - /* Needed to automatically set `updated_by` fields on insertions and updates */ - CREATE FUNCTION trigger_set_updated_by() - RETURNS TRIGGER AS $$ - BEGIN - NEW.updated_by = current_user; - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - "#, - r#" - /* Set up ownership related triggers */ - DO - $$ - DECLARE - t_name text; - BEGIN - FOR t_name IN (VALUES ('compiled_contracts'), - ('verified_contracts')) - LOOP - EXECUTE format('CREATE TRIGGER insert_set_created_by - BEFORE INSERT ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_created_by()', - t_name); - - EXECUTE format('CREATE TRIGGER insert_set_updated_by - BEFORE INSERT ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_updated_by()', - t_name); - - EXECUTE format('CREATE TRIGGER update_reuse_created_by - BEFORE UPDATE ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_reuse_created_by()', - t_name); - - EXECUTE format('CREATE TRIGGER update_set_updated_by - BEFORE UPDATE ON %I - FOR EACH ROW - EXECUTE FUNCTION trigger_set_updated_by()', - t_name); - END LOOP; - END; - $$ LANGUAGE plpgsql; - "#, - ]; - statements.into_iter().map(Into::into).collect() -} - -fn drop_ownership_triggers() -> Vec { - let sql = r#" - DROP FUNCTION trigger_set_created_by; - DROP FUNCTION trigger_reuse_created_by; - DROP FUNCTION trigger_set_updated_by; - "#; - sql.split(';').map(Into::into).collect() -} diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20241028_143125_initialize_schema_v1.rs b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20241028_143125_initialize_schema_v1.rs new file mode 100644 index 000000000..b84892f1b --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/m20241028_143125_initialize_schema_v1.rs @@ -0,0 +1,19 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let sql = include_str!("./migrations/initialize_schema_v1_up.sql"); + manager.get_connection().execute_unprepared(sql).await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let sql = include_str!("./migrations/initialize_schema_v1_down.sql"); + manager.get_connection().execute_unprepared(sql).await?; + Ok(()) + } +} diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_down.sql b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_down.sql new file mode 100644 index 000000000..47c93a354 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_down.sql @@ -0,0 +1,48 @@ +DROP TABLE verified_contracts; +DROP TABLE compiled_contracts_sources; +DROP TABLE sources; +DROP TABLE compiled_contracts; +DROP TABLE contract_deployments; +DROP TABLE contracts; +DROP TABLE code; + +DROP FUNCTION trigger_set_updated_by; +DROP FUNCTION trigger_reuse_created_by; +DROP FUNCTION trigger_set_created_by; + +DROP FUNCTION trigger_set_updated_at; +DROP FUNCTION trigger_reuse_created_at; +DROP FUNCTION trigger_set_created_at; + +DROP FUNCTION validate_runtime_transformations; +DROP FUNCTION validate_creation_transformations; +DROP FUNCTION validate_transformations; +DROP FUNCTION validate_transformations_call_protection; +DROP FUNCTION validate_transformations_cbor_auxdata; +DROP FUNCTION validate_transformations_immutable; +DROP FUNCTION validate_transformations_library; +DROP FUNCTION validate_transformations_constructor_arguments; +DROP FUNCTION validate_transformation_key_id; +DROP FUNCTION validate_transformation_key_offset; +DROP FUNCTION validate_transformation_key_type; + +DROP FUNCTION validate_runtime_values; +DROP FUNCTION validate_creation_values; +DROP FUNCTION validate_values_call_protection; +DROP FUNCTION validate_values_cbor_auxdata; +DROP FUNCTION validate_values_immutables; +DROP FUNCTION validate_values_libraries; +DROP FUNCTION validate_values_constructor_arguments; + +DROP FUNCTION validate_runtime_code_artifacts; +DROP FUNCTION validate_creation_code_artifacts; +DROP FUNCTION validate_compilation_artifacts; + +DROP FUNCTION validate_json_object_keys; +DROP FUNCTION is_valid_hex; +DROP FUNCTION is_jsonb_number; +DROP FUNCTION is_jsonb_array; +DROP FUNCTION is_jsonb_string; +DROP FUNCTION is_jsonb_object; + +DROP EXTENSION pgcrypto; \ No newline at end of file diff --git a/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_up.sql b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_up.sql new file mode 100644 index 000000000..c78498dd5 --- /dev/null +++ b/eth-bytecode-db/eth-bytecode-db/verifier-alliance-migration/src/migrations/initialize_schema_v1_up.sql @@ -0,0 +1,859 @@ +/* Needed for gen_random_uuid() and digest(..) */ +CREATE EXTENSION pgcrypto; + +/* + The `code` table stores a mapping from code hash to bytecode. This table may store + both normalized and unnormalized code. + + Code is normalized when all libraries/immutable variables that are not constants are + replaced with zeroes. In other words the variable `address private immutable FACTORY = 0xAABB...EEFF;` + would not be replaced with zeroes, but the variable `address private immutable OWNER = msg.sender` would. + + The `code` column is not marked NOT NULL because we need to distinguish between + empty code, and no code. Empty code occurs when a contract is deployed with no runtime code. + No code occurs when a contract's code is written directly to the chain in a hard fork +*/ +CREATE TABLE code +( + /* the sha256 hash of the `code` column */ + code_hash bytea NOT NULL PRIMARY KEY, + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + /* + the keccak256 hash of the `code` column + + can be useful for lookups, as keccak256 is more common for Ethereum + but we cannot use it as a primary key because postgres does not support the keccak256, and + we cannot guarantee at the database level that provided value is the correct `code` hash + */ + code_hash_keccak bytea NOT NULL, + + /* the bytecode */ + code bytea + + CONSTRAINT code_hash_check + CHECK (code IS NOT NULL and code_hash = digest(code, 'sha256') or code IS NULL and code_hash = '\x'::bytea) + ); + +CREATE INDEX code_code_hash_keccak ON code USING btree(code_hash_keccak); + +/* ensure the sentinel value exists */ +INSERT INTO code (code_hash, code_hash_keccak, code) VALUES ('\x', '\x', NULL); + +/* + The `contracts` table stores information which can be used to identify a unique contract in a + chain-agnostic manner. In other words, suppose you deploy the same contract on two chains, all + properties that would be shared across the two chains should go in this table because they uniquely + identify the contract. +*/ +CREATE TABLE contracts +( + /* an opaque id */ + id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + /* + the creation code is the calldata (for eoa creations) or the instruction input (for create/create2) + the runtime code is the bytecode that's returned by the creation code and stored on-chain + + neither fields are normalized + */ + creation_code_hash bytea NOT NULL REFERENCES code (code_hash), + runtime_code_hash bytea NOT NULL REFERENCES code (code_hash), + + CONSTRAINT contracts_pseudo_pkey UNIQUE (creation_code_hash, runtime_code_hash) +); + +CREATE INDEX contracts_creation_code_hash ON contracts USING btree(creation_code_hash); +CREATE INDEX contracts_runtime_code_hash ON contracts USING btree(runtime_code_hash); +CREATE INDEX contracts_creation_code_hash_runtime_code_hash ON contracts USING btree(creation_code_hash, runtime_code_hash); + +/* + The `contract_deployments` table stores information about a specific deployment unique to a chain. + One contract address may have multiple deployments on a single chain if SELFDESTRUCT/CREATE2 is used + The info stored in this table should be retrievable from an archive node. In other words, it should + not be augmented with any inferred data +*/ +CREATE TABLE contract_deployments +( + /* an opaque id*/ + id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + /* + these three fields uniquely identify a specific deployment of a contract, assuming + that it is impossible to deploy to successfully an address twice in the same transaction + (create2 -> selfdestruct -> create2 should revert on the second create2) + + in the case of a "genesis" contract, the transaction_hash should be set + to keccak256(creation_code_hash || runtime_code_hash). this is because the transaction_hash + needs to differ to distinguish between two versions of the same genesis contract, and so + it needs to embed inside it the only feature that changes. + + also note that for genesis contracts, creation_code_hash may be '\x' (i.e. there is no creation code) + */ + chain_id numeric NOT NULL, + address bytea NOT NULL, + transaction_hash bytea NOT NULL, + + /* + geth full nodes have the ability to prune the transaction index, so if the transaction_hash + can't be found directly, use the block_number and transaction_index. make sure to compare the transaction_hash to + make sure it matches! + + for genesis contracts, both values should be set to -1 + */ + block_number numeric NOT NULL, + transaction_index numeric NOT NULL, + + /* + this is the address which actually deployed the contract (i.e. called the create/create2 opcode) + */ + deployer bytea NOT NULL, + + /* the contract itself */ + contract_id uuid NOT NULL REFERENCES contracts(id), + + CONSTRAINT contract_deployments_pseudo_pkey UNIQUE (chain_id, address, transaction_hash) +); + +CREATE INDEX contract_deployments_contract_id ON contract_deployments USING btree(contract_id); + +/* + The `compiled_contracts` table stores information about a specific compilation. A compilation is + defined as a set of inputs (compiler settings, source code, etc) which uniquely correspond to a + set of outputs (bytecode, documentation, ast, etc) +*/ +CREATE TABLE compiled_contracts +( + /* an opaque id */ + id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + /* + these three fields uniquely identify the high-level compiler mode to use + + note that the compiler is the software ('solc', 'vyper', 'huff') while language is + the syntax ('solidity', 'vyper', 'yul'). there may be future compilers which aren't solc + but can still compile solidity, which is why we need to differentiate the two + + the version should uniquely identify the compiler + */ + compiler VARCHAR NOT NULL, + version VARCHAR NOT NULL, + language VARCHAR NOT NULL, + + /* + the name is arbitrary and often not a factor in verifying contracts (solidity encodes it in + the auxdata which we ignore, and vyper doesn't even have the concept of sourceunit-level names) + because of this we don't include it in the unique constraint. it is stored purely for informational + purposes + */ + name VARCHAR NOT NULL, + + /* the fully qualified name is compiler-specific and indicates exactly which contract to look for */ + fully_qualified_name VARCHAR NOT NULL, + + /* compiler-specific settings such as optimization, linking, etc (string => any) */ + compiler_settings jsonb NOT NULL, + + /* general and compiler-specific artifacts (abi, userdoc, devdoc, licenses, etc) */ + compilation_artifacts jsonb NOT NULL, + + /* + note that we can't pull out creation/runtime code into its own table + imagine that a future compiler and language combo result in the same bytecode + this is something that we would want a record of, because the two sources are semantically + unique + in other words, the hypothetical table would need to be keyed on everything that this table already is + */ + + /* these fields store info about the creation code (sourcemaps, linkreferences) */ + creation_code_hash bytea NOT NULL REFERENCES code (code_hash), + creation_code_artifacts jsonb NOT NULL, + + /* + these fields store info about the runtime code (sourcemaps, linkreferences, immutables) + the runtime code should be normalized (i.e. immutables set to zero) + */ + runtime_code_hash bytea NOT NULL REFERENCES code (code_hash), + runtime_code_artifacts jsonb NOT NULL, + + /* + two different compilers producing the same bytecode is unique enough that we want to preserve it + the same compiler with two different versions producing the same bytecode is not unique (f.ex nightlies) + */ + CONSTRAINT compiled_contracts_pseudo_pkey UNIQUE (compiler, language, creation_code_hash, runtime_code_hash) +); + +CREATE INDEX compiled_contracts_creation_code_hash ON compiled_contracts USING btree (creation_code_hash); +CREATE INDEX compiled_contracts_runtime_code_hash ON compiled_contracts USING btree (runtime_code_hash); + +/* + The `sources` table stores the source code related to the contracts. + It includes hashes of the source code and the code content itself. +*/ +CREATE TABLE sources +( + /* the sha256 hash of the source code */ + source_hash bytea NOT NULL PRIMARY KEY, + + /* the keccak256 hash of the source code */ + source_hash_keccak bytea NOT NULL, + + /* the actual source code content */ + content varchar NOT NULL, + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + CONSTRAINT source_hash_check CHECK (source_hash = digest(content, 'sha256')) +); + +/* + The `compiled_contracts_sources` table links a compiled_contract to its associated source files. + This table contains a unique combination of compilation_id and path. +*/ +CREATE TABLE compiled_contracts_sources +( + id uuid NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(), + + /* the specific compilation and the specific source */ + compilation_id uuid NOT NULL REFERENCES compiled_contracts(id), + source_hash bytea NOT NULL REFERENCES sources(source_hash), + + /* the file path associated with this source code in the compilation */ + path varchar NOT NULL, + + CONSTRAINT compiled_contracts_sources_pseudo_pkey UNIQUE (compilation_id, path) +); + +CREATE INDEX compiled_contracts_sources_source_hash ON compiled_contracts_sources USING btree (source_hash); +CREATE INDEX compiled_contracts_sources_compilation_id ON compiled_contracts_sources (compilation_id); + +/* + The verified_contracts table links an on-chain contract with a compiled_contract + Note that only one of creation or runtime bytecode must match, because: + We could get a creation match but runtime mismatch if the contract is a proxy that uses assembly to return custom runtime bytecode + We could get a runtime match but creation mismatch if the contract is deployed via a create2 factory +*/ +CREATE TABLE verified_contracts +( + /* an opaque id, but sequentially ordered */ + id BIGSERIAL NOT NULL PRIMARY KEY, + + /* timestamps */ + created_at timestamptz NOT NULL DEFAULT NOW(), + updated_at timestamptz NOT NULL DEFAULT NOW(), + + /* ownership */ + created_by varchar NOT NULL DEFAULT (current_user), + updated_by varchar NOT NULL DEFAULT (current_user), + + /* the specific deployment and the specific compilation */ + deployment_id uuid NOT NULL REFERENCES contract_deployments (id), + compilation_id uuid NOT NULL REFERENCES compiled_contracts (id), + + /* + if the code matches, then the values and transformation fields contain + all the information required to transform the compiled bytecode to the deployed bytecode + see the json schemas provided for more information + */ + + creation_match bool NOT NULL, + creation_values jsonb, + creation_transformations jsonb, + creation_metadata_match bool, + + runtime_match bool NOT NULL, + runtime_values jsonb, + runtime_transformations jsonb, + runtime_metadata_match bool, + + CONSTRAINT verified_contracts_pseudo_pkey UNIQUE (compilation_id, deployment_id), + + CONSTRAINT verified_contracts_match_exists + CHECK (creation_match = true OR runtime_match = true), + CONSTRAINT verified_contracts_creation_match_integrity + CHECK ((creation_match = false AND creation_values IS NULL AND creation_transformations IS NULL AND creation_metadata_match IS NULL) OR + (creation_match = true AND creation_values IS NOT NULL AND creation_transformations IS NOT NULL AND creation_metadata_match IS NOT NULL)), + CONSTRAINT verified_contracts_runtime_match_integrity + CHECK ((runtime_match = false AND runtime_values IS NULL AND runtime_transformations IS NULL AND runtime_metadata_match IS NULL) OR + (runtime_match = true AND runtime_values IS NOT NULL AND runtime_transformations IS NOT NULL AND runtime_metadata_match IS NOT NULL)) +); + +CREATE INDEX verified_contracts_deployment_id ON verified_contracts USING btree (deployment_id); +CREATE INDEX verified_contracts_compilation_id ON verified_contracts USING btree (compilation_id); + +/* + Helper functions used to ensure the correctness of json objects. +*/ +CREATE OR REPLACE FUNCTION is_jsonb_object(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + jsonb_typeof(obj) = 'object'; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION is_jsonb_string(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + jsonb_typeof(obj) = 'string'; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION is_jsonb_array(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + jsonb_typeof(obj) = 'array'; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION is_jsonb_number(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + jsonb_typeof(obj) = 'number'; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION is_valid_hex(val text, repetition text) + RETURNS boolean AS +$$ +BEGIN +RETURN val SIMILAR TO CONCAT('0x([0-9|a-f|A-F][0-9|a-f|A-F])', repetition); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_json_object_keys(obj jsonb, mandatory_keys text[], optional_keys text[]) + RETURNS boolean AS +$$ +BEGIN +RETURN + -- ensures that all keys on the right exist as keys inside obj + obj ?& mandatory_keys AND + -- check that no unknown key exists inside obj + bool_and(obj_keys = any (mandatory_keys || optional_keys)) + from (select obj_keys from jsonb_object_keys(obj) as obj_keys) as subquery; +END; +$$ LANGUAGE plpgsql; + +/* + Validation functions to be used in `compiled_contracts` artifact constraints. +*/ +CREATE OR REPLACE FUNCTION validate_compilation_artifacts(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_object(obj) AND + validate_json_object_keys( + obj, + array ['abi', 'userdoc', 'devdoc', 'sources', 'storageLayout'], + array []::text[] + ); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_creation_code_artifacts(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_object(obj) AND + validate_json_object_keys( + obj, + array ['sourceMap', 'linkReferences'], + array ['cborAuxdata'] + ); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_runtime_code_artifacts(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_object(obj) AND + validate_json_object_keys( + obj, + array ['sourceMap', 'linkReferences', 'immutableReferences'], + array ['cborAuxdata'] + ); +END; +$$ LANGUAGE plpgsql; + + +ALTER TABLE compiled_contracts + ADD CONSTRAINT compilation_artifacts_json_schema + CHECK (validate_compilation_artifacts(compilation_artifacts)); + +ALTER TABLE compiled_contracts + ADD CONSTRAINT creation_code_artifacts_json_schema + CHECK (validate_creation_code_artifacts(creation_code_artifacts)); + +ALTER TABLE compiled_contracts + ADD CONSTRAINT runtime_code_artifacts_json_schema + CHECK (validate_runtime_code_artifacts(runtime_code_artifacts)); + +/* + Validation functions to be used in `verified_contracts` values constraints. +*/ +CREATE OR REPLACE FUNCTION validate_values_constructor_arguments(obj jsonb) + RETURNS boolean AS +$$ +BEGIN + -- `obj` does not contain 'constructorArguments' key + IF NOT obj ? 'constructorArguments' THEN + RETURN true; +END IF; + +RETURN is_jsonb_string(obj -> 'constructorArguments') + AND is_valid_hex(obj ->> 'constructorArguments', '+'); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_values_libraries(obj jsonb) + RETURNS boolean AS +$$ +BEGIN + -- `obj` does not contain 'libraries' key + IF NOT obj ? 'libraries' THEN + RETURN true; +END IF; + + -- we have to use IF, so that internal select subquery is executed only when `obj -> 'libraries'` is an object + IF is_jsonb_object(obj -> 'libraries') THEN + RETURN bool_and(are_valid_values) + FROM (SELECT is_jsonb_string(value) AND is_valid_hex(value ->> 0, '{20}') as are_valid_values + FROM jsonb_each(obj -> 'libraries')) as subquery; +ELSE + RETURN false; +END IF; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_values_immutables(obj jsonb) + RETURNS boolean AS +$$ +BEGIN + -- `obj` does not contain 'immutables' key + IF NOT obj ? 'immutables' THEN + RETURN true; +END IF; + + IF is_jsonb_object(obj -> 'immutables') THEN + RETURN bool_and(are_valid_values) + FROM (SELECT is_jsonb_string(value) AND is_valid_hex(value ->> 0, '{32}') as are_valid_values + FROM jsonb_each(obj -> 'immutables')) as subquery; +ELSE + RETURN false; +END IF; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_values_cbor_auxdata(obj jsonb) + RETURNS boolean AS +$$ +BEGIN + -- `obj` does not contain 'cborAuxdata' key + IF NOT obj ? 'cborAuxdata' THEN + RETURN true; +END IF; + + IF is_jsonb_object(obj -> 'cborAuxdata') THEN + RETURN bool_and(are_valid_values) + FROM (SELECT is_jsonb_string(value) AND is_valid_hex(value ->> 0, '+') as are_valid_values + FROM jsonb_each(obj -> 'cborAuxdata')) as subquery; +ELSE + RETURN false; +END IF; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_values_call_protection(obj jsonb) + RETURNS boolean AS +$$ +BEGIN + -- `obj` does not contain 'callProtection' key + IF NOT obj ? 'callProtection' THEN + RETURN true; +END IF; + +RETURN is_jsonb_string(obj -> 'callProtection') + AND is_valid_hex(obj ->> 'callProtection', '{20}'); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_creation_values(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_object(obj) AND + validate_json_object_keys( + obj, + array []::text[], + array ['constructorArguments', 'libraries', 'cborAuxdata'] + ) AND + validate_values_constructor_arguments(obj) AND + validate_values_libraries(obj) AND + validate_values_cbor_auxdata(obj); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_runtime_values(obj jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_object(obj) AND + validate_json_object_keys( + obj, + array []::text[], + array ['libraries', 'immutables', 'cborAuxdata', 'callProtection'] + ) AND + validate_values_libraries(obj) AND + validate_values_immutables(obj) AND + validate_values_cbor_auxdata(obj) AND + validate_values_call_protection(obj); +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION validate_transformation_key_type(object jsonb, expected_value text) + RETURNS boolean AS +$$ +BEGIN +RETURN object ? 'type' AND is_jsonb_string(object -> 'type') AND object ->> 'type' = expected_value; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformation_key_offset(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN object ? 'offset' AND is_jsonb_number(object -> 'offset') AND (object ->> 'offset')::integer >= 0; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformation_key_id(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN object ? 'id' AND is_jsonb_string(object -> 'id') AND length(object ->> 'id') > 0; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformations_constructor_arguments(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN validate_transformation_key_type(object, 'insert') AND validate_transformation_key_offset(object); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformations_library(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformations_immutable(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformations_cbor_auxdata(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object) + AND validate_transformation_key_id(object); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_transformations_call_protection(object jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN validate_transformation_key_type(object, 'replace') AND validate_transformation_key_offset(object); +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION validate_transformations(transformations jsonb, allowed_reasons text[]) + RETURNS boolean AS +$$ +DECLARE +transformation_object jsonb; + reason text; +BEGIN +FOR transformation_object IN SELECT * FROM jsonb_array_elements(transformations) + LOOP + IF NOT is_jsonb_object(transformation_object) + OR NOT transformation_object ? 'reason' + OR NOT is_jsonb_string(transformation_object -> 'reason') + OR array_position(allowed_reasons, transformation_object ->> 'reason') IS NULL + THEN + RETURN false; +END IF; + + reason := transformation_object ->> 'reason'; + +CASE + WHEN reason = 'constructorArguments' + THEN RETURN validate_transformations_constructor_arguments(transformation_object); +WHEN reason = 'library' THEN RETURN validate_transformations_library(transformation_object); +WHEN reason = 'immutable' THEN RETURN validate_transformations_immutable(transformation_object); +WHEN reason = 'cborAuxdata' THEN RETURN validate_transformations_cbor_auxdata(transformation_object); +WHEN reason = 'callProtection' + THEN RETURN validate_transformations_call_protection(transformation_object); +ELSE +END CASE; + +END LOOP; + +RETURN true; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_creation_transformations(transformations jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_array(transformations) AND + validate_transformations(transformations, array ['constructorArguments', 'library', 'cborAuxdata']); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION validate_runtime_transformations(transformations jsonb) + RETURNS boolean AS +$$ +BEGIN +RETURN + is_jsonb_array(transformations) AND + validate_transformations(transformations, array ['library', 'immutable', 'cborAuxdata', 'callProtection']); +END; +$$ LANGUAGE plpgsql; + +ALTER TABLE verified_contracts + ADD CONSTRAINT creation_values_json_schema + CHECK (creation_values IS NULL OR validate_creation_values(creation_values)); + +ALTER TABLE verified_contracts + ADD CONSTRAINT runtime_values_json_schema + CHECK (runtime_values IS NULL OR validate_runtime_values(runtime_values)); + +ALTER TABLE verified_contracts + ADD CONSTRAINT creation_transformations_json_schema + CHECK (creation_transformations IS NULL OR validate_creation_transformations(creation_transformations)); + +ALTER TABLE verified_contracts + ADD CONSTRAINT runtime_transformations_json_schema + CHECK (runtime_transformations IS NULL OR validate_runtime_transformations(runtime_transformations)); + +/* + Set up timestamps related triggers. Used to enforce `created_at` and `updated_at` + specific rules and prevent users to set those columns to invalid values. + Spefically: + `created_at` - should be set to the current timestamp on new row insertion, + and should not be modified after that. + `updated_at` - should be set to the current timestamp on new row insertion, + and should be always be updated the corresponding value is modified. +*/ + +/* Needed to automatically set `created_at` fields on insertions. */ +CREATE FUNCTION trigger_set_created_at() + RETURNS TRIGGER AS $$ +BEGIN + NEW.created_at = NOW(); +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +/* Needed to prevent modifying `crerated_at` fields on updates */ +CREATE FUNCTION trigger_reuse_created_at() + RETURNS TRIGGER AS + $$ +BEGIN + NEW.created_at = OLD.created_at; +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +/* Needed to automatically set `updated_at` fields on insertions and updates */ +CREATE FUNCTION trigger_set_updated_at() + RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +DO +$$ + DECLARE +t_name text; +BEGIN +FOR t_name IN (VALUES ('code'), + ('contracts'), + ('contract_deployments'), + ('compiled_contracts'), + ('sources'), + ('verified_contracts')) + LOOP + EXECUTE format('CREATE TRIGGER insert_set_created_at + BEFORE INSERT ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_created_at()', + t_name); + +EXECUTE format('CREATE TRIGGER insert_set_updated_at + BEFORE INSERT ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_updated_at()', + t_name); + +EXECUTE format('CREATE TRIGGER update_reuse_created_at + BEFORE UPDATE ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_reuse_created_at()', + t_name); + +EXECUTE format('CREATE TRIGGER update_set_updated_at + BEFORE UPDATE ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_updated_at()', + t_name); +END LOOP; +END; +$$ LANGUAGE plpgsql; + +/* + Set up ownership (who inserted the value) related triggers. + Used to enforce `created_by` and `updated_by` specific rules and prevent users to + set those columns to invalid values. + Spefically: + `created_by` - should be set to the current user on new row insertion, + and should not be modified after that. + `updated_by` - should be set to the current user on new row insertion, + and should be always be updated the corresponding value is modified. +*/ + +/* Needed to automatically set `created_by` fields on insertions. */ +CREATE FUNCTION trigger_set_created_by() + RETURNS TRIGGER AS $$ +BEGIN + NEW.created_by = current_user; +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +/* Needed to prevent modifying `crerated_by` fields on updates */ +CREATE FUNCTION trigger_reuse_created_by() + RETURNS TRIGGER AS + $$ +BEGIN + NEW.created_by = OLD.created_by; +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +/* Needed to automatically set `updated_by` fields on insertions and updates */ +CREATE FUNCTION trigger_set_updated_by() + RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_by = current_user; +RETURN NEW; +END; +$$ LANGUAGE plpgsql; + + +/* Set up ownership related triggers */ +DO +$$ + DECLARE +t_name text; +BEGIN +FOR t_name IN (VALUES ('code'), + ('contracts'), + ('contract_deployments'), + ('compiled_contracts'), + ('sources'), + ('verified_contracts')) + LOOP + EXECUTE format('CREATE TRIGGER insert_set_created_by + BEFORE INSERT ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_created_by()', + t_name); + +EXECUTE format('CREATE TRIGGER insert_set_updated_by + BEFORE INSERT ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_updated_by()', + t_name); + +EXECUTE format('CREATE TRIGGER update_reuse_created_by + BEFORE UPDATE ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_reuse_created_by()', + t_name); + +EXECUTE format('CREATE TRIGGER update_set_updated_by + BEFORE UPDATE ON %I + FOR EACH ROW + EXECUTE FUNCTION trigger_set_updated_by()', + t_name); +END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/eth-bytecode-db/verifier-alliance-database/Cargo.toml b/eth-bytecode-db/verifier-alliance-database/Cargo.toml new file mode 100644 index 000000000..28f539d4a --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "verifier-alliance-database" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +blockscout-display-bytes = { workspace = true } +keccak-hash = { workspace = true } +sea-orm = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +sha3 = { workspace = true } +strum = { workspace = true } +verification-common-v1 = { workspace = true } +verifier-alliance-entity-v1 = { workspace = true } + +[dev-dependencies] +blockscout-service-launcher = { workspace = true, features = ["test-database"] } +pretty_assertions = { workspace = true } +serde_json = { workspace = true } +serde_with = { workspace = true } +tokio = { workspace = true, features = ["macros"] } +verifier-alliance-migration-v1 = { workspace = true } diff --git a/eth-bytecode-db/verifier-alliance-database/src/helpers.rs b/eth-bytecode-db/verifier-alliance-database/src/helpers.rs new file mode 100644 index 000000000..ee1801e73 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/src/helpers.rs @@ -0,0 +1,91 @@ +use anyhow::Context; +use sea_orm::{ + sea_query::OnConflict, ActiveModelBehavior, ActiveModelTrait, ColumnTrait, ConnectionTrait, + DbErr, EntityTrait, IntoActiveModel, ModelTrait, PrimaryKeyToColumn, QueryFilter, +}; + +pub async fn insert_then_select( + txn: &C, + entity: Entity, + active_model: ActiveModel, + unique_columns: impl IntoIterator, +) -> Result<(Entity::Model, bool), anyhow::Error> +where + C: ConnectionTrait, + Entity: EntityTrait, + ActiveModel: ActiveModelTrait + ActiveModelBehavior + Send, + ::Model: IntoActiveModel, +{ + insert_then_select_internal(txn, entity, active_model, unique_columns, false).await +} + +async fn insert_then_select_internal( + txn: &C, + entity: Entity, + active_model: ActiveModel, + unique_columns: impl IntoIterator, + update_on_conflict: bool, +) -> Result<(Entity::Model, bool), anyhow::Error> +where + C: ConnectionTrait, + Entity: EntityTrait, + ActiveModel: ActiveModelTrait + ActiveModelBehavior + Send, + ::Model: IntoActiveModel, +{ + let entity_table_name = entity.table_name(); + + let result: Result<_, DbErr> = Entity::insert(active_model.clone()) + .on_conflict(OnConflict::new().do_nothing().to_owned()) + .exec(txn) + .await; + + // Returns the model and the bool flag showing whether the model was actually inserted. + match result { + Ok(res) => { + let last_insert_id = res.last_insert_id; + let id_debug_str = format!("{last_insert_id:?}"); + let model = Entity::find_by_id(last_insert_id) + .one(txn) + .await + .context(format!("select from \"{entity_table_name}\" by \"id\""))? + .ok_or(anyhow::anyhow!( + "select from \"{entity_table_name}\" by \"id\"={id_debug_str} returned no data" + ))?; + + Ok((model, true)) + } + Err(DbErr::RecordNotInserted) => { + let mut query = Entity::find(); + for (column, value) in unique_columns { + query = query.filter(column.eq(value)); + } + let mut model = query + .one(txn) + .await + .context(format!( + "select from \"{entity_table_name}\" by unique columns" + ))? + .ok_or(anyhow::anyhow!( + "select from \"{entity_table_name}\" by unique columns returned no data" + ))?; + + // The active model have not been inserted. + // Thus, there were a value already that we need to update. + if update_on_conflict { + let mut active_model_to_update = active_model; + for primary_key in ::iter() { + let column = PrimaryKeyToColumn::into_column(primary_key); + let value = ModelTrait::get(&model, column); + ActiveModelTrait::set(&mut active_model_to_update, column, value); + } + model = active_model_to_update + .update(txn) + .await + .context(format!("update on conflict in \"{entity_table_name}\""))?; + } + + Ok((model, false)) + } + Err(err) => Err(err).context(format!("insert into \"{entity_table_name}\"")), + } +} diff --git a/eth-bytecode-db/verifier-alliance-database/src/internal.rs b/eth-bytecode-db/verifier-alliance-database/src/internal.rs new file mode 100644 index 000000000..abc18d5ec --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/src/internal.rs @@ -0,0 +1,487 @@ +use crate::helpers; +use anyhow::{anyhow, Context, Error}; +use blockscout_display_bytes::ToHex; +use sea_orm::{ + prelude::{Decimal, Uuid}, + ActiveValue::Set, + ColumnTrait, ConnectionTrait, EntityTrait, QueryFilter, +}; +use sha2::{Digest, Sha256}; +use sha3::Keccak256; +use std::collections::BTreeMap; +use verification_common_v1::verifier_alliance::Match; +use verifier_alliance_entity_v1::{ + code, compiled_contracts, compiled_contracts_sources, contract_deployments, contracts, sources, + verified_contracts, +}; + +pub use crate::types::{ + CompiledContract, CompiledContractCompiler, CompiledContractLanguage, ContractCode, + InsertContractDeployment, RetrieveContractDeployment, VerifiedContract, + VerifiedContractMatches, +}; + +#[derive(Clone, Debug)] +pub struct InternalContractDeploymentData { + pub chain_id: Decimal, + pub address: Vec, + pub transaction_hash: Vec, + pub block_number: Decimal, + pub transaction_index: Decimal, + pub deployer: Vec, + pub contract_code: ContractCode, +} + +impl From for InternalContractDeploymentData { + fn from(value: InsertContractDeployment) -> Self { + match value { + InsertContractDeployment::Genesis { .. } => parse_genesis_contract_deployment(value), + InsertContractDeployment::Regular { .. } => parse_regular_contract_deployment(value), + } + } +} + +#[derive(Clone, Debug, Default)] +struct InternalMatchData { + does_match: bool, + metadata_match: Option, + values: Option, + transformations: Option, +} + +pub async fn insert_verified_contract( + database_connection: &C, + contract_deployment_id: Uuid, + compiled_contract_id: Uuid, + matches: VerifiedContractMatches, +) -> Result { + let (creation_match_data, runtime_match_data) = match matches { + VerifiedContractMatches::OnlyRuntime { runtime_match } => { + let runtime_match_data = parse_verification_common_match(runtime_match); + (InternalMatchData::default(), runtime_match_data) + } + VerifiedContractMatches::OnlyCreation { creation_match } => { + let creation_match_data = parse_verification_common_match(creation_match); + (creation_match_data, InternalMatchData::default()) + } + VerifiedContractMatches::Complete { + runtime_match, + creation_match, + } => { + let creation_match_data = parse_verification_common_match(creation_match); + let runtime_match_data = parse_verification_common_match(runtime_match); + (creation_match_data, runtime_match_data) + } + }; + + let active_model = verified_contracts::ActiveModel { + id: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + deployment_id: Set(contract_deployment_id), + compilation_id: Set(compiled_contract_id), + creation_match: Set(creation_match_data.does_match), + creation_values: Set(creation_match_data.values), + creation_transformations: Set(creation_match_data.transformations), + creation_metadata_match: Set(creation_match_data.metadata_match), + runtime_match: Set(runtime_match_data.does_match), + runtime_values: Set(runtime_match_data.values), + runtime_transformations: Set(runtime_match_data.transformations), + runtime_metadata_match: Set(runtime_match_data.metadata_match), + }; + + use verified_contracts::Column; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + verified_contracts::Entity, + active_model, + [ + (Column::CompilationId, compiled_contract_id.into()), + (Column::DeploymentId, contract_deployment_id.into()), + ], + ) + .await?; + + Ok(model) +} + +pub async fn insert_compiled_contract( + database_connection: &C, + compiled_contract: CompiledContract, +) -> Result { + let creation_code_hash = insert_code(database_connection, compiled_contract.creation_code) + .await + .context("insert creation code")? + .code_hash; + let runtime_code_hash = insert_code(database_connection, compiled_contract.runtime_code) + .await + .context("insert runtime code")? + .code_hash; + + let active_model = compiled_contracts::ActiveModel { + id: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + compiler: Set(compiled_contract.compiler.to_string()), + version: Set(compiled_contract.version), + language: Set(compiled_contract.language.to_string()), + name: Set(compiled_contract.name), + fully_qualified_name: Set(compiled_contract.fully_qualified_name), + compiler_settings: Set(compiled_contract.compiler_settings), + compilation_artifacts: Set(compiled_contract.compilation_artifacts.into()), + creation_code_hash: Set(creation_code_hash.clone()), + creation_code_artifacts: Set(compiled_contract.creation_code_artifacts.into()), + runtime_code_hash: Set(runtime_code_hash.clone()), + runtime_code_artifacts: Set(compiled_contract.runtime_code_artifacts.into()), + }; + + use compiled_contracts::Column; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + compiled_contracts::Entity, + active_model, + [ + ( + Column::Compiler, + compiled_contract.compiler.to_string().into(), + ), + ( + Column::Language, + compiled_contract.language.to_string().into(), + ), + (Column::CreationCodeHash, creation_code_hash.into()), + (Column::RuntimeCodeHash, runtime_code_hash.into()), + ], + ) + .await?; + + Ok(model) +} + +pub async fn insert_sources( + database_connection: &C, + sources: BTreeMap, +) -> Result, Error> { + let mut models = vec![]; + + for (_path, content) in sources { + let source_hash = Sha256::digest(&content).to_vec(); + let source_hash_keccak = Keccak256::digest(&content).to_vec(); + let active_model = sources::ActiveModel { + source_hash: Set(source_hash.clone()), + source_hash_keccak: Set(source_hash_keccak), + content: Set(content), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + }; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + sources::Entity, + active_model, + [(sources::Column::SourceHash, source_hash.into())], + ) + .await?; + models.push(model) + } + + Ok(models) +} + +pub async fn insert_compiled_contract_sources( + database_connection: &C, + source_hashes: BTreeMap>, + compiled_contract_id: Uuid, +) -> Result, Error> { + let mut models = vec![]; + + for (path, source_hash) in source_hashes { + let active_model = compiled_contracts_sources::ActiveModel { + id: Default::default(), + compilation_id: Set(compiled_contract_id), + path: Set(path.clone()), + source_hash: Set(source_hash), + }; + use compiled_contracts_sources::Column; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + compiled_contracts_sources::Entity, + active_model, + [ + (Column::CompilationId, compiled_contract_id.into()), + (Column::Path, path.into()), + ], + ) + .await?; + models.push(model); + } + + Ok(models) +} + +pub async fn insert_contract_deployment( + database_connection: &C, + internal_data: InternalContractDeploymentData, + contract_id: Uuid, +) -> Result { + let active_model = contract_deployments::ActiveModel { + id: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + chain_id: Set(internal_data.chain_id), + address: Set(internal_data.address.clone()), + transaction_hash: Set(internal_data.transaction_hash.clone()), + block_number: Set(internal_data.block_number), + transaction_index: Set(internal_data.transaction_index), + deployer: Set(internal_data.deployer), + contract_id: Set(contract_id), + }; + + use contract_deployments::Column; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + contract_deployments::Entity, + active_model, + [ + (Column::ChainId, internal_data.chain_id.into()), + (Column::Address, internal_data.address.into()), + ( + Column::TransactionHash, + internal_data.transaction_hash.into(), + ), + ], + ) + .await?; + + Ok(model) +} + +pub async fn retrieve_contract_deployment( + database_connection: &C, + contract_deployment: RetrieveContractDeployment, +) -> Result, Error> { + let transaction_hash = contract_deployment.transaction_hash.unwrap_or_else(|| { + let runtime_code = contract_deployment + .runtime_code + .expect("either transaction hash or runtime code must contain value"); + calculate_genesis_contract_deployment_transaction_hash(&runtime_code) + }); + + contract_deployments::Entity::find() + .filter( + contract_deployments::Column::ChainId.eq(Decimal::from(contract_deployment.chain_id)), + ) + .filter(contract_deployments::Column::Address.eq(contract_deployment.address)) + .filter(contract_deployments::Column::TransactionHash.eq(transaction_hash)) + .one(database_connection) + .await + .context("select from \"contract_deployments\"") +} + +pub async fn insert_contract( + database_connection: &C, + contract_code: ContractCode, +) -> Result { + let (creation_code_hash, runtime_code_hash) = + insert_contract_code(database_connection, contract_code).await?; + + let active_model = contracts::ActiveModel { + id: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + creation_code_hash: Set(creation_code_hash.clone()), + runtime_code_hash: Set(runtime_code_hash.clone()), + }; + + use contracts::Column; + let (model, _inserted) = helpers::insert_then_select( + database_connection, + contracts::Entity, + active_model, + [ + (Column::CreationCodeHash, creation_code_hash.into()), + (Column::RuntimeCodeHash, runtime_code_hash.into()), + ], + ) + .await?; + + Ok(model) +} + +pub async fn insert_code( + database_connection: &C, + code: Vec, +) -> Result { + let code_hash = Sha256::digest(&code).to_vec(); + let code_hash_keccak = Keccak256::digest(&code).to_vec(); + + let active_model = code::ActiveModel { + code_hash: Set(code_hash.clone()), + created_at: Default::default(), + updated_at: Default::default(), + created_by: Default::default(), + updated_by: Default::default(), + code_hash_keccak: Set(code_hash_keccak), + code: Set(Some(code)), + }; + + let (model, _inserted) = helpers::insert_then_select( + database_connection, + code::Entity, + active_model, + [(code::Column::CodeHash, code_hash.into())], + ) + .await?; + + Ok(model) +} + +/// Inserts a contract defined by its runtime and creation code into `contracts` table. +/// Notice, that only creation code is optional, while runtime code should always exist. +/// It can be empty though, in case creation code execution resulted in empty code. +/// Creation code may be missed for genesis contracts. +async fn insert_contract_code( + database_connection: &C, + contract_code: ContractCode, +) -> Result<(Vec, Vec), Error> { + let mut creation_code_hash = vec![]; + let runtime_code_hash; + + match contract_code { + ContractCode::OnlyRuntimeCode { code } => { + runtime_code_hash = insert_code(database_connection, code) + .await + .context("insert runtime code")? + .code_hash; + } + ContractCode::CompleteCode { + creation_code, + runtime_code, + } => { + creation_code_hash = insert_code(database_connection, creation_code) + .await + .context("insert creation code")? + .code_hash; + runtime_code_hash = insert_code(database_connection, runtime_code) + .await + .context("insert runtime code")? + .code_hash; + } + } + + Ok((creation_code_hash, runtime_code_hash)) +} + +pub async fn retrieve_contract_by_id( + database_connection: &C, + contract_id: Uuid, +) -> Result { + contracts::Entity::find_by_id(contract_id) + .one(database_connection) + .await + .context("select from \"contracts\" by id")? + .ok_or_else(|| anyhow!("contract id was not found: {}", contract_id)) +} + +pub async fn retrieve_code_by_id( + database_connection: &C, + code_hash: Vec, +) -> Result { + code::Entity::find_by_id(code_hash.clone()) + .one(database_connection) + .await + .context("select from \"code\" by id")? + .ok_or_else(|| anyhow!("code hash was not found: {}", code_hash.to_hex())) +} + +pub fn precalculate_source_hashes(sources: &BTreeMap) -> BTreeMap> { + let mut source_hashes = BTreeMap::new(); + for (path, content) in sources { + let source_hash = Sha256::digest(content).to_vec(); + source_hashes.insert(path.clone(), source_hash); + } + + source_hashes +} + +fn parse_genesis_contract_deployment( + contract_deployment: InsertContractDeployment, +) -> InternalContractDeploymentData { + if let InsertContractDeployment::Genesis { + chain_id, + address, + runtime_code, + } = contract_deployment + { + let transaction_hash = + calculate_genesis_contract_deployment_transaction_hash(&runtime_code); + let contract_code = ContractCode::OnlyRuntimeCode { code: runtime_code }; + + return InternalContractDeploymentData { + chain_id: Decimal::from(chain_id), + address, + transaction_hash, + block_number: Decimal::from(-1), + transaction_index: Decimal::from(-1), + deployer: vec![], + contract_code, + }; + } + + unreachable!() +} + +fn parse_regular_contract_deployment( + contract_deployment: InsertContractDeployment, +) -> InternalContractDeploymentData { + if let InsertContractDeployment::Regular { + chain_id, + address, + transaction_hash, + block_number, + transaction_index, + deployer, + creation_code, + runtime_code, + } = contract_deployment + { + let contract_code = ContractCode::CompleteCode { + creation_code, + runtime_code, + }; + + return InternalContractDeploymentData { + chain_id: Decimal::from(chain_id), + address, + transaction_hash, + block_number: Decimal::from(block_number), + transaction_index: Decimal::from(transaction_index), + deployer, + contract_code, + }; + } + + unreachable!() +} + +fn calculate_genesis_contract_deployment_transaction_hash(runtime_code: &[u8]) -> Vec { + Keccak256::digest(runtime_code).to_vec() +} + +fn parse_verification_common_match(match_value: Match) -> InternalMatchData { + InternalMatchData { + does_match: true, + metadata_match: Some(match_value.metadata_match), + values: Some(match_value.values.into()), + transformations: Some(match_value.transformations.into()), + } +} diff --git a/eth-bytecode-db/verifier-alliance-database/src/lib.rs b/eth-bytecode-db/verifier-alliance-database/src/lib.rs new file mode 100644 index 000000000..8c8731389 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/src/lib.rs @@ -0,0 +1,132 @@ +/// Provides access to internal functions to access the database. +/// They mostly do not provide transactions consistency, and require +/// users to be care of transactions themselves. +/// +/// Are not recommended to be used directly. +/// Prefer methods exposed to the public instead. +pub mod internal; + +mod helpers; +mod types; + +pub use types::{ + CompiledContract, CompiledContractCompiler, CompiledContractLanguage, ContractCode, + ContractDeployment, InsertContractDeployment, RetrieveContractDeployment, VerifiedContract, + VerifiedContractMatches, +}; + +/************************ Public methods **************************/ + +use anyhow::{anyhow, Context, Error}; +use sea_orm::{DatabaseConnection, TransactionTrait}; + +pub async fn insert_contract_deployment( + database_connection: &DatabaseConnection, + to_insert: InsertContractDeployment, +) -> Result { + let chain_id = to_insert.chain_id(); + let address = to_insert.address().to_owned(); + let creation_code = to_insert.creation_code().map(ToOwned::to_owned); + let runtime_code = to_insert.runtime_code().to_owned(); + + let transaction = database_connection + .begin() + .await + .context("begin transaction")?; + + let internal_data = internal::InternalContractDeploymentData::from(to_insert); + let contract_model = + internal::insert_contract(&transaction, internal_data.contract_code.clone()).await?; + let contract_deployment_model = + internal::insert_contract_deployment(&transaction, internal_data, contract_model.id) + .await?; + + transaction.commit().await.context("commit transaction")?; + + Ok(ContractDeployment { + id: contract_deployment_model.id, + chain_id, + address, + runtime_code, + creation_code, + model: contract_deployment_model, + }) +} + +pub async fn insert_verified_contract( + database_connection: &DatabaseConnection, + mut verified_contract: VerifiedContract, +) -> Result<(), Error> { + let transaction = database_connection + .begin() + .await + .context("begin transaction")?; + + let sources = std::mem::take(&mut verified_contract.compiled_contract.sources); + let source_hashes = internal::precalculate_source_hashes(&sources); + + let compiled_contract_model = + internal::insert_compiled_contract(&transaction, verified_contract.compiled_contract) + .await?; + let compiled_contract_id = compiled_contract_model.id; + + let _source_models = internal::insert_sources(&transaction, sources).await?; + let _compiled_contract_source_models = internal::insert_compiled_contract_sources( + &transaction, + source_hashes, + compiled_contract_id, + ) + .await?; + let _verified_contract_model = internal::insert_verified_contract( + &transaction, + verified_contract.contract_deployment_id, + compiled_contract_id, + verified_contract.matches, + ) + .await?; + + transaction.commit().await.context("commit transaction")?; + + Ok(()) +} + +pub async fn find_contract_deployment( + database_connection: &DatabaseConnection, + to_retrieve: RetrieveContractDeployment, +) -> Result, Error> { + let chain_id = to_retrieve.chain_id(); + let address = to_retrieve.address().to_owned(); + + let contract_deployment_model = + internal::retrieve_contract_deployment(database_connection, to_retrieve).await?; + if let Some(contract_deployment_model) = contract_deployment_model { + let contract = internal::retrieve_contract_by_id( + database_connection, + contract_deployment_model.contract_id, + ) + .await?; + + let creation_code_model = + internal::retrieve_code_by_id(database_connection, contract.creation_code_hash.clone()) + .await?; + let creation_code = creation_code_model.code; + + let runtime_code_model = + internal::retrieve_code_by_id(database_connection, contract.runtime_code_hash.clone()) + .await?; + let runtime_code = runtime_code_model + .code + .ok_or(anyhow!("contract does not have runtime code"))?; + + return Ok(Some(ContractDeployment { + id: contract_deployment_model.id, + chain_id, + address, + runtime_code, + creation_code, + model: contract_deployment_model, + })); + } + + Ok(None) +} diff --git a/eth-bytecode-db/verifier-alliance-database/src/types.rs b/eth-bytecode-db/verifier-alliance-database/src/types.rs new file mode 100644 index 000000000..b75ddc62e --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/src/types.rs @@ -0,0 +1,164 @@ +use sea_orm::prelude::Uuid; +use std::collections::BTreeMap; +use verification_common_v1::verifier_alliance::{ + CompilationArtifacts, CreationCodeArtifacts, Match, RuntimeCodeArtifacts, +}; +use verifier_alliance_entity_v1::contract_deployments; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ContractDeployment { + pub id: Uuid, + pub chain_id: u128, + pub address: Vec, + pub runtime_code: Vec, + pub creation_code: Option>, + pub model: contract_deployments::Model, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ContractCode { + OnlyRuntimeCode { + code: Vec, + }, + CompleteCode { + creation_code: Vec, + runtime_code: Vec, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum InsertContractDeployment { + Genesis { + chain_id: u128, + address: Vec, + runtime_code: Vec, + }, + Regular { + chain_id: u128, + address: Vec, + transaction_hash: Vec, + block_number: u128, + transaction_index: u128, + deployer: Vec, + creation_code: Vec, + runtime_code: Vec, + }, +} + +impl InsertContractDeployment { + pub fn chain_id(&self) -> u128 { + match self { + InsertContractDeployment::Genesis { chain_id, .. } => *chain_id, + InsertContractDeployment::Regular { chain_id, .. } => *chain_id, + } + } + + pub fn address(&self) -> &[u8] { + match self { + InsertContractDeployment::Genesis { address, .. } => address, + InsertContractDeployment::Regular { address, .. } => address, + } + } + + pub fn runtime_code(&self) -> &[u8] { + match self { + InsertContractDeployment::Genesis { runtime_code, .. } => runtime_code, + InsertContractDeployment::Regular { runtime_code, .. } => runtime_code, + } + } + + pub fn creation_code(&self) -> Option<&[u8]> { + match self { + InsertContractDeployment::Genesis { .. } => None, + InsertContractDeployment::Regular { creation_code, .. } => Some(creation_code), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct RetrieveContractDeployment { + pub(crate) chain_id: u128, + pub(crate) address: Vec, + pub(crate) transaction_hash: Option>, + pub(crate) runtime_code: Option>, +} + +impl RetrieveContractDeployment { + pub fn regular(chain_id: u128, address: Vec, transaction_hash: Vec) -> Self { + Self { + chain_id, + address, + transaction_hash: Some(transaction_hash), + runtime_code: None, + } + } + + pub fn genesis(chain_id: u128, address: Vec, runtime_code: Vec) -> Self { + Self { + chain_id, + address, + transaction_hash: None, + runtime_code: Some(runtime_code), + } + } + + pub fn chain_id(&self) -> u128 { + self.chain_id + } + + pub fn address(&self) -> &[u8] { + &self.address + } +} + +#[derive(Clone, Debug, strum::Display, strum::EnumString, PartialEq, Eq, Hash)] +#[strum(serialize_all = "lowercase")] +pub enum CompiledContractCompiler { + Solc, + Vyper, +} + +#[derive(Clone, Debug, strum::Display, strum::EnumString, PartialEq, Eq, Hash)] +#[strum(serialize_all = "lowercase")] +pub enum CompiledContractLanguage { + Solidity, + Yul, + Vyper, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CompiledContract { + pub compiler: CompiledContractCompiler, + pub version: String, + pub language: CompiledContractLanguage, + pub name: String, + pub fully_qualified_name: String, + pub sources: BTreeMap, + pub compiler_settings: serde_json::Value, + pub compilation_artifacts: CompilationArtifacts, + pub creation_code: Vec, + pub creation_code_artifacts: CreationCodeArtifacts, + pub runtime_code: Vec, + pub runtime_code_artifacts: RuntimeCodeArtifacts, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum VerifiedContractMatches { + OnlyCreation { + creation_match: Match, + }, + OnlyRuntime { + runtime_match: Match, + }, + Complete { + creation_match: Match, + runtime_match: Match, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct VerifiedContract { + pub contract_deployment_id: Uuid, + pub compiled_contract: CompiledContract, + pub matches: VerifiedContractMatches, +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/contract_deployments.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/contract_deployments.rs new file mode 100644 index 000000000..bee3ccc2c --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/contract_deployments.rs @@ -0,0 +1,111 @@ +use blockscout_display_bytes::decode_hex; +use blockscout_service_launcher::test_database::database; +use pretty_assertions::assert_eq; +use verifier_alliance_database::{InsertContractDeployment, RetrieveContractDeployment}; +use verifier_alliance_migration_v1::Migrator; + +#[tokio::test] +async fn insert_regular_deployment_works_and_can_be_retrieved() { + let db_guard = database!(Migrator); + + let chain_id = 10; + let address = decode_hex("0x8FbB39A5a79aeCE03c8f13ccEE0b96C128ec1a67").unwrap(); + let transaction_hash = + decode_hex("0xf4042e19c445551d1059ad3856f83383c48699367cfb3e0edeccd26002dd2292").unwrap(); + + let contract_deployment = InsertContractDeployment::Regular { + chain_id, + address: address.clone(), + transaction_hash: transaction_hash.clone(), + block_number: 127387809, + transaction_index: 16, + deployer: decode_hex("0x1F98431c8aD98523631AE4a59f267346ea31F984").unwrap(), + creation_code: vec![0x1, 0x2], + runtime_code: vec![0x3, 0x4], + }; + + let inserted_model = verifier_alliance_database::insert_contract_deployment( + db_guard.client().as_ref(), + contract_deployment, + ) + .await + .expect("error while inserting"); + + /********** retrieval **********/ + + let retrieve_contract_deployment = + RetrieveContractDeployment::regular(chain_id, address, transaction_hash); + + let retrieved_model = verifier_alliance_database::find_contract_deployment( + db_guard.client().as_ref(), + retrieve_contract_deployment, + ) + .await + .expect("error while retrieving") + .expect("no model has been retrieved"); + + assert_eq!( + inserted_model, retrieved_model, + "inserted and retrieved models do not match" + ); +} + +#[tokio::test] +async fn insert_genesis_deployment_works_and_can_be_retrieved() { + let db_guard = database!(Migrator); + + let chain_id = 10; + let address = decode_hex("0x4200000000000000000000000000000000000008").unwrap(); + let runtime_code = vec![0x3, 0x4]; + + let contract_deployment = InsertContractDeployment::Genesis { + chain_id: 10, + address: address.clone(), + runtime_code: runtime_code.clone(), + }; + + let inserted_model = verifier_alliance_database::insert_contract_deployment( + db_guard.client().as_ref(), + contract_deployment, + ) + .await + .expect("error while inserting"); + + /********** retrieval **********/ + + let retrieve_contract_deployment = + RetrieveContractDeployment::genesis(chain_id, address, runtime_code); + + let retrieved_model = verifier_alliance_database::find_contract_deployment( + db_guard.client().as_ref(), + retrieve_contract_deployment, + ) + .await + .expect("error while retrieving") + .expect("no model has been retrieved"); + + assert_eq!( + inserted_model, retrieved_model, + "inserted and retrieved models do not match" + ); +} + +#[tokio::test] +async fn non_existed_deployment_retrieval_returns_none() { + let db_guard = database!(Migrator); + + let retrieve_contract_deployment = + RetrieveContractDeployment::regular(10, vec![0x1], vec![0x1]); + + let retrieved_model = verifier_alliance_database::find_contract_deployment( + db_guard.client().as_ref(), + retrieve_contract_deployment, + ) + .await + .expect("error while retrieving"); + + assert_eq!( + None, retrieved_model, + "no model was expected to be retrieved" + ); +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/internal_compiled_contracts.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/internal_compiled_contracts.rs new file mode 100644 index 000000000..30ca667a7 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/internal_compiled_contracts.rs @@ -0,0 +1,96 @@ +use blockscout_service_launcher::test_database::database; +use serde_json::json; +use std::collections::BTreeMap; +use verification_common_v1::verifier_alliance::{ + CompilationArtifacts, CreationCodeArtifacts, RuntimeCodeArtifacts, SourceId, +}; +use verifier_alliance_database::{ + internal, CompiledContract, CompiledContractCompiler, CompiledContractLanguage, +}; +use verifier_alliance_migration_v1::Migrator; + +#[tokio::test] +async fn insert_compiled_contract_works() { + let db_guard = database!(Migrator); + + let compiled_contract = CompiledContract { + compiler: CompiledContractCompiler::Solc, + version: "".to_string(), + language: CompiledContractLanguage::Solidity, + name: "Counter".to_string(), + fully_qualified_name: "src/Counter.sol:Counter".to_string(), + sources: BTreeMap::from([( + "src/Counter.sol".into(), + "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Counter {\n uint256 public number;\n\n function setNumber(uint256 newNumber) public {\n number = newNumber;\n }\n\n function increment() public {\n number++;\n }\n}\n".into(), + )]), + compiler_settings: json!({"evmVersion":"paris","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"*":["*"]}},"remappings":[],"viaIR":false}), + compilation_artifacts: CompilationArtifacts { + abi: Some(json!({"abi": "value"})), + devdoc: Some(json!({"devdoc": "value"})), + userdoc: Some(json!({"userdoc": "value"})), + storage_layout: Some(json!({"storage": "value"})), + sources: Some(BTreeMap::from([("src/Counter.sol".into(), SourceId {id: 0})])) + }, + creation_code: vec![0x1, 0x2], + creation_code_artifacts: CreationCodeArtifacts { + source_map: Some(json!("source_map")), + link_references: Some(json!({"linkReferences": "value"})), + cbor_auxdata: Some(json!({"cborAuxdata": "value"})), + }, + runtime_code: vec![0x3, 0x4], + runtime_code_artifacts: RuntimeCodeArtifacts { + cbor_auxdata: Some(json!({"cborAuxdata": "value"})), + immutable_references: Some(json!({"immutableReferences": "value"})), + link_references: Some(json!({"linkReferences": "value"})), + source_map: Some(json!("source_map")), + }, + }; + + let _inserted_model = + internal::insert_compiled_contract(db_guard.client().as_ref(), compiled_contract) + .await + .expect("error while inserting"); +} + +#[tokio::test] +async fn insert_compiled_contract_with_empty_artifact_values() { + let db_guard = database!(Migrator); + + let compiled_contract = CompiledContract { + compiler: CompiledContractCompiler::Solc, + version: "".to_string(), + language: CompiledContractLanguage::Solidity, + name: "Counter".to_string(), + fully_qualified_name: "src/Counter.sol:Counter".to_string(), + sources: BTreeMap::from([( + "src/Counter.sol".into(), + "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Counter {\n uint256 public number;\n\n function setNumber(uint256 newNumber) public {\n number = newNumber;\n }\n\n function increment() public {\n number++;\n }\n}\n".into(), + )]), + compiler_settings: json!({"evmVersion":"paris","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"*":["*"]}},"remappings":[],"viaIR":false}), + compilation_artifacts: CompilationArtifacts { + abi: None, + devdoc: None, + userdoc: None, + storage_layout: None, + sources: None, + }, + creation_code: vec![0x1, 0x2], + creation_code_artifacts: CreationCodeArtifacts { + source_map: None, + link_references: None, + cbor_auxdata: None, + }, + runtime_code: vec![0x3, 0x4], + runtime_code_artifacts: RuntimeCodeArtifacts { + cbor_auxdata: None, + immutable_references: None, + link_references: None, + source_map: None, + }, + }; + + let _inserted_model = + internal::insert_compiled_contract(db_guard.client().as_ref(), compiled_contract) + .await + .expect("error while inserting"); +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/main.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/main.rs new file mode 100644 index 000000000..a6b7e2b14 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/main.rs @@ -0,0 +1,5 @@ +mod contract_deployments; +mod internal_compiled_contracts; +mod transformations; +mod transformations_types; +mod verified_contracts; diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations.rs new file mode 100644 index 000000000..4bfdbfd1f --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations.rs @@ -0,0 +1,48 @@ +use crate::transformations_types::TestCase; +use blockscout_service_launcher::test_database::database; +use verifier_alliance_database::{insert_contract_deployment, insert_verified_contract}; +use verifier_alliance_migration_v1::Migrator; + +macro_rules! build_test { + ($test_name:ident) => { + #[tokio::test] + async fn $test_name() { + const TEST_CASE_CONTENT: &str = include_str!(std::concat!( + "../test_cases/", + stringify!($test_name), + ".json" + )); + + let database_guard = database!(Migrator); + let database_connection = database_guard.client(); + + let test_case = TestCase::from_content(TEST_CASE_CONTENT); + + let contract_deployment_data = test_case.contract_deployment_data(); + let inserted_contract_deployment = + insert_contract_deployment(&database_connection, contract_deployment_data) + .await + .expect("error while inserting contract deployment"); + + let verified_contract_data = + test_case.verified_contract_data(inserted_contract_deployment.id); + let _inserted_verified_contract = + insert_verified_contract(&database_connection, verified_contract_data) + .await + .expect("error while inserting verified contract"); + + test_case + .validate_final_database_state(&database_connection) + .await; + } + }; +} + +build_test!(constructor_arguments); +build_test!(full_match); +build_test!(immutables); +build_test!(libraries_linked_by_compiler); +build_test!(libraries_manually_linked); +build_test!(metadata_hash_absent); +build_test!(partial_match); +build_test!(partial_match_double_auxdata); diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations_types.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations_types.rs new file mode 100644 index 000000000..e82402c29 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/transformations_types.rs @@ -0,0 +1,451 @@ +use sea_orm::{prelude::Uuid, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; +use serde::{Deserialize, Deserializer}; +use serde_json::Value; +use sha3::{Digest, Keccak256}; +use std::{collections::BTreeMap, str::FromStr}; +use verification_common_v1::verifier_alliance::{ + CompilationArtifacts, CreationCodeArtifacts, Match, MatchTransformation, MatchValues, + RuntimeCodeArtifacts, +}; +use verifier_alliance_database::{ + CompiledContract, CompiledContractCompiler, CompiledContractLanguage, InsertContractDeployment, + VerifiedContract, VerifiedContractMatches, +}; +use verifier_alliance_entity_v1::{ + code, compiled_contracts, compiled_contracts_sources, contract_deployments, contracts, sources, + verified_contracts, +}; + +#[serde_with::serde_as] +#[derive(Clone, Debug, Deserialize)] +pub struct TestCase { + #[serde(deserialize_with = "string_to_u128")] + chain_id: u128, + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + address: Vec, + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + transaction_hash: Vec, + #[serde(deserialize_with = "string_to_u128")] + block_number: u128, + #[serde(deserialize_with = "string_to_u128")] + transaction_index: u128, + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + deployer: Vec, + + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + deployed_creation_code: Vec, + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + deployed_runtime_code: Vec, + + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + compiled_creation_code: Vec, + #[serde_as(as = "blockscout_display_bytes::serde_as::Hex")] + compiled_runtime_code: Vec, + + compiler: String, + version: String, + language: String, + name: String, + fully_qualified_name: String, + sources: BTreeMap, + compiler_settings: Value, + compilation_artifacts: CompilationArtifacts, + creation_code_artifacts: CreationCodeArtifacts, + runtime_code_artifacts: RuntimeCodeArtifacts, + + #[serde(rename = "creation_match")] + _creation_match: bool, + creation_metadata_match: bool, + creation_values: MatchValues, + creation_transformations: Vec, + + #[serde(rename = "runtime_match")] + _runtime_match: bool, + runtime_metadata_match: bool, + runtime_values: MatchValues, + runtime_transformations: Vec, +} + +fn string_to_u128<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let string = String::deserialize(deserializer)?; + u128::from_str(&string).map_err(::custom) +} + +impl TestCase { + pub fn from_content(content: &str) -> Self { + serde_json::from_str(content).expect("invalid test case format") + } + + pub fn contract_deployment_data(&self) -> InsertContractDeployment { + InsertContractDeployment::Regular { + chain_id: self.chain_id, + address: self.address.clone(), + transaction_hash: self.transaction_hash.clone(), + block_number: self.block_number, + transaction_index: self.transaction_index, + deployer: self.deployer.clone(), + creation_code: self.deployed_creation_code.clone(), + runtime_code: self.deployed_runtime_code.clone(), + } + } + + pub fn verified_contract_data(&self, contract_deployment_id: Uuid) -> VerifiedContract { + let compiler = CompiledContractCompiler::from_str(&self.compiler.to_lowercase()) + .expect("invalid compiler"); + let language = CompiledContractLanguage::from_str(&self.language.to_lowercase()) + .expect("invalid language"); + VerifiedContract { + contract_deployment_id, + compiled_contract: CompiledContract { + compiler, + version: self.version.clone(), + language, + name: self.name.clone(), + fully_qualified_name: self.fully_qualified_name.clone(), + sources: self.sources.clone(), + compiler_settings: self.compiler_settings.clone(), + compilation_artifacts: self.compilation_artifacts.clone(), + creation_code: self.compiled_creation_code.clone(), + creation_code_artifacts: self.creation_code_artifacts.clone(), + runtime_code: self.compiled_runtime_code.clone(), + runtime_code_artifacts: self.runtime_code_artifacts.clone(), + }, + matches: VerifiedContractMatches::Complete { + creation_match: Match { + metadata_match: self.creation_metadata_match, + transformations: self.creation_transformations.clone(), + values: self.creation_values.clone(), + }, + runtime_match: Match { + metadata_match: self.runtime_metadata_match, + transformations: self.runtime_transformations.clone(), + values: self.runtime_values.clone(), + }, + }, + } + } +} + +impl TestCase { + pub async fn validate_final_database_state(&self, database_connection: &DatabaseConnection) { + let _contract_deployment = self + .validate_contract_deployments_table(database_connection) + .await; + let contract = self.validate_contracts_table(database_connection).await; + self.validate_code_value( + database_connection, + contract.creation_code_hash, + self.deployed_creation_code.clone(), + ) + .await; + self.validate_code_value( + database_connection, + contract.runtime_code_hash, + self.deployed_runtime_code.clone(), + ) + .await; + + let compiled_contract = self + .validate_compiled_contracts_table(database_connection) + .await; + self.validate_code_value( + database_connection, + compiled_contract.creation_code_hash, + self.compiled_creation_code.clone(), + ) + .await; + self.validate_code_value( + database_connection, + compiled_contract.runtime_code_hash, + self.compiled_runtime_code.clone(), + ) + .await; + + let sources = self.validate_sources_table(database_connection).await; + let _compiled_contracts_sources = self + .validate_compiled_contracts_sources_table(database_connection, sources) + .await; + + let _verified_contracts = self + .validate_verified_contracts_table(database_connection) + .await; + } + + async fn validate_contract_deployments_table( + &self, + database_connection: &DatabaseConnection, + ) -> contract_deployments::Model { + let contract_deployments = contract_deployments::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving contract deployments"); + assert_eq!( + contract_deployments.len(), + 1, + "invalid number of contract deployments in the database: {:?}", + contract_deployments + ); + let contract_deployment = contract_deployments[0].clone(); + + assert_eq!( + contract_deployment.address, + self.address.clone(), + "invalid contract deployment address" + ); + assert_eq!( + contract_deployment.chain_id, + self.chain_id.into(), + "invalid contract deployment chain id" + ); + assert_eq!( + contract_deployment.transaction_hash, self.transaction_hash, + "invalid contract deployment transaction hash" + ); + assert_eq!( + contract_deployment.block_number, + self.block_number.into(), + "invalid contract deployment block number" + ); + assert_eq!( + contract_deployment.transaction_index, + self.transaction_index.into(), + "invalid contract deployment transaction index" + ); + assert_eq!( + contract_deployment.deployer, self.deployer, + "invalid contract deployment deployer" + ); + + contract_deployment + } + + async fn validate_contracts_table( + &self, + database_connection: &DatabaseConnection, + ) -> contracts::Model { + let contracts = contracts::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving contracts"); + assert_eq!( + contracts.len(), + 1, + "invalid number of contracts in the database: {:?}", + contracts + ); + contracts[0].clone() + } + + async fn validate_code_value( + &self, + database_connection: &DatabaseConnection, + code_hash: Vec, + code: Vec, + ) -> code::Model { + let code_model = code::Entity::find() + .filter(code::Column::CodeHash.eq(code_hash.clone())) + .one(database_connection) + .await + .expect("error while retrieving code value") + .unwrap_or_else(|| panic!("code hash does not exist in the database: {:?}", code_hash)); + + let expected_code_hash_keccak = Keccak256::digest(&code).to_vec(); + assert_eq!( + code_model.code_hash_keccak, expected_code_hash_keccak, + "invalid code code hash keccak" + ); + assert_eq!(code_model.code, Some(code), "invalid code value"); + + code_model + } + + async fn validate_compiled_contracts_table( + &self, + database_connection: &DatabaseConnection, + ) -> compiled_contracts::Model { + let compiled_contracts = compiled_contracts::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving compiled contracts"); + assert_eq!( + compiled_contracts.len(), + 1, + "invalid number of compiled contracts in the database: {:?}", + compiled_contracts + ); + let compiled_contract = compiled_contracts[0].clone(); + + assert_eq!( + compiled_contract.compiler.to_string(), + self.compiler, + "invalid compiled contract compiler" + ); + assert_eq!( + compiled_contract.version, self.version, + "invalid compiled contract version" + ); + assert_eq!( + compiled_contract.language.to_string(), + self.language, + "invalid compiled contract language" + ); + assert_eq!( + compiled_contract.name, self.name, + "invalid compiled contract name" + ); + assert_eq!( + compiled_contract.fully_qualified_name, self.fully_qualified_name, + "invalid compiled contract fully qualified name" + ); + assert_eq!( + compiled_contract.compiler_settings, self.compiler_settings, + "invalid compiled contract compiler settings" + ); + assert_eq!( + compiled_contract.compilation_artifacts, + Value::from(self.compilation_artifacts.clone()), + "invalid compiled contract compilation artifacts" + ); + assert_eq!( + compiled_contract.creation_code_artifacts, + Value::from(self.creation_code_artifacts.clone()), + "invalid compiled contract creation code artifacts" + ); + assert_eq!( + compiled_contract.runtime_code_artifacts, + Value::from(self.runtime_code_artifacts.clone()), + "invalid compiled contract runtime artifacts" + ); + + compiled_contract + } + + async fn validate_sources_table( + &self, + database_connection: &DatabaseConnection, + ) -> Vec { + let sources = sources::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving sources"); + assert_eq!( + sources.len(), + self.sources.len(), + "invalid number of sources in database: {:?}", + sources + ); + + for (path, content) in self.sources.iter() { + let source = sources + .iter() + .find(|source| &source.content == content) + .unwrap_or_else(|| panic!("source not found in the database for path={path}")); + let expected_source_hash_keccak = Keccak256::digest(&source.content).to_vec(); + assert_eq!( + source.source_hash_keccak, expected_source_hash_keccak, + "invalid source source hash keccak" + ); + } + + sources + } + + async fn validate_compiled_contracts_sources_table( + &self, + database_connection: &DatabaseConnection, + sources: Vec, + ) -> Vec { + let compiled_contracts_sources = compiled_contracts_sources::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving compiled contracts sources"); + assert_eq!( + compiled_contracts_sources.len(), + sources.len(), + "invalid number of compiled contracts sources in the database: {:?}", + compiled_contracts_sources + ); + + for (path, content) in self.sources.iter() { + let compiled_contract_source = compiled_contracts_sources + .iter() + .find(|model| &model.path == path) + .unwrap_or_else(|| { + panic!("compiled contract source not found in database for path={path}") + }); + let source = sources + .iter() + .find(|source| &source.content == content) + .unwrap(); + let expected_source_hash = &source.source_hash; + assert_eq!( + &compiled_contract_source.source_hash, expected_source_hash, + "invalid compiled contract source source hash" + ); + } + + compiled_contracts_sources + } + + async fn validate_verified_contracts_table( + &self, + database_connection: &DatabaseConnection, + ) -> verified_contracts::Model { + let verified_contracts = verified_contracts::Entity::find() + .all(database_connection) + .await + .expect("error while retrieving verified contracts"); + assert_eq!( + verified_contracts.len(), + 1, + "invalid number of verified contracts in database: {:?}", + verified_contracts + ); + let verified_contract = verified_contracts[0].clone(); + + assert!( + verified_contract.creation_match, + "invalid verified contract creation match" + ); + assert_eq!( + verified_contract.creation_metadata_match, + Some(self.creation_metadata_match), + "invalid verified contract creation metadata match" + ); + assert_eq!( + verified_contract.creation_values, + Some(Value::from(self.creation_values.clone())), + "invalid verified contract creation values" + ); + assert_eq!( + verified_contract.creation_transformations, + Some(Value::from(self.creation_transformations.clone())), + "invalid verified contract creation transformations" + ); + + assert!( + verified_contract.runtime_match, + "invalid verified contract runtime match" + ); + assert_eq!( + verified_contract.runtime_metadata_match, + Some(self.runtime_metadata_match), + "invalid verified contract runtime metadata match" + ); + assert_eq!( + verified_contract.runtime_values, + Some(Value::from(self.runtime_values.clone())), + "invalid verified contract runtime values" + ); + assert_eq!( + verified_contract.runtime_transformations, + Some(Value::from(self.runtime_transformations.clone())), + "invalid verified contract runtime transformations" + ); + + verified_contract + } +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/integration/verified_contracts.rs b/eth-bytecode-db/verifier-alliance-database/tests/integration/verified_contracts.rs new file mode 100644 index 000000000..82f537edb --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/integration/verified_contracts.rs @@ -0,0 +1,238 @@ +use blockscout_display_bytes::decode_hex; +use blockscout_service_launcher::test_database::database; +use sea_orm::{prelude::Uuid, DatabaseConnection}; +use serde_json::json; +use std::collections::BTreeMap; +use verification_common_v1::verifier_alliance::{ + CompilationArtifacts, CreationCodeArtifacts, Match, MatchTransformation, MatchValues, + RuntimeCodeArtifacts, SourceId, +}; +use verifier_alliance_database::{ + CompiledContract, CompiledContractCompiler, CompiledContractLanguage, InsertContractDeployment, + VerifiedContract, VerifiedContractMatches, +}; +use verifier_alliance_migration_v1::Migrator; + +#[tokio::test] +async fn insert_verified_contract_with_complete_matches_work() { + let db_guard = database!(Migrator); + + let contract_deployment_id = insert_contract_deployment(db_guard.client().as_ref()).await; + let compiled_contract = complete_compiled_contract(); + let verified_contract = VerifiedContract { + contract_deployment_id, + compiled_contract, + matches: VerifiedContractMatches::Complete { + runtime_match: Match { + metadata_match: true, + transformations: vec![], + values: Default::default(), + }, + creation_match: Match { + metadata_match: true, + transformations: vec![], + values: Default::default(), + }, + }, + }; + + verifier_alliance_database::insert_verified_contract( + db_guard.client().as_ref(), + verified_contract, + ) + .await + .expect("error while inserting"); +} + +#[tokio::test] +async fn insert_verified_contract_with_runtime_only_matches_work() { + let db_guard = database!(Migrator); + + let contract_deployment_id = insert_contract_deployment(db_guard.client().as_ref()).await; + let compiled_contract = complete_compiled_contract(); + let verified_contract = VerifiedContract { + contract_deployment_id, + compiled_contract, + matches: VerifiedContractMatches::OnlyRuntime { + runtime_match: Match { + metadata_match: true, + transformations: vec![], + values: Default::default(), + }, + }, + }; + + verifier_alliance_database::insert_verified_contract( + db_guard.client().as_ref(), + verified_contract, + ) + .await + .expect("error while inserting"); +} + +#[tokio::test] +async fn insert_verified_contract_with_creation_only_matches_work() { + let db_guard = database!(Migrator); + + let contract_deployment_id = insert_contract_deployment(db_guard.client().as_ref()).await; + let compiled_contract = complete_compiled_contract(); + let verified_contract = VerifiedContract { + contract_deployment_id, + compiled_contract, + matches: VerifiedContractMatches::OnlyCreation { + creation_match: Match { + metadata_match: true, + transformations: vec![], + values: Default::default(), + }, + }, + }; + + verifier_alliance_database::insert_verified_contract( + db_guard.client().as_ref(), + verified_contract, + ) + .await + .expect("error while inserting"); +} + +#[tokio::test] +async fn insert_verified_contract_with_filled_matches() { + let db_guard = database!(Migrator); + + let contract_deployment_id = insert_contract_deployment(db_guard.client().as_ref()).await; + let compiled_contract = complete_compiled_contract(); + + let (runtime_match_values, runtime_match_transformations) = { + let mut match_values = MatchValues::default(); + let mut match_transformations = vec![]; + + match_values.add_immutable( + "immutable", + decode_hex("0x0000000000000000000000000000000000000000000000000000000000000032") + .unwrap() + .into(), + ); + match_transformations.push(MatchTransformation::immutable(1, "immutable")); + match_values.add_library( + "library", + decode_hex("0x0000000000000000000000000000000000000020") + .unwrap() + .into(), + ); + match_transformations.push(MatchTransformation::library(1, "library")); + match_values.add_cbor_auxdata( + "cborAuxdata", + decode_hex("0x1000000000000000000000000000000000000000000000000000000000000032") + .unwrap() + .into(), + ); + match_transformations.push(MatchTransformation::auxdata(1, "cborAuxdata")); + + (match_values, match_transformations) + }; + + let (creation_match_values, creation_match_transformations) = { + let mut match_values = MatchValues::default(); + let mut match_transformations = vec![]; + + match_values.add_constructor_arguments(decode_hex("0x01020304").unwrap().into()); + match_transformations.push(MatchTransformation::constructor(1)); + match_values.add_library( + "library", + decode_hex("0x0000000000000000000000000000000000000020") + .unwrap() + .into(), + ); + match_transformations.push(MatchTransformation::library(1, "library")); + match_values.add_cbor_auxdata( + "cborAuxdata", + decode_hex("0x1000000000000000000000000000000000000000000000000000000000000032") + .unwrap() + .into(), + ); + match_transformations.push(MatchTransformation::auxdata(1, "cborAuxdata")); + + (match_values, match_transformations) + }; + + let verified_contract = VerifiedContract { + contract_deployment_id, + compiled_contract, + matches: VerifiedContractMatches::Complete { + runtime_match: Match { + metadata_match: false, + transformations: runtime_match_transformations, + values: runtime_match_values, + }, + creation_match: Match { + metadata_match: false, + transformations: creation_match_transformations, + values: creation_match_values, + }, + }, + }; + + verifier_alliance_database::insert_verified_contract( + db_guard.client().as_ref(), + verified_contract, + ) + .await + .expect("error while inserting"); +} + +fn complete_compiled_contract() -> CompiledContract { + CompiledContract { + compiler: CompiledContractCompiler::Solc, + version: "".to_string(), + language: CompiledContractLanguage::Solidity, + name: "Counter".to_string(), + fully_qualified_name: "src/Counter.sol:Counter".to_string(), + sources: BTreeMap::from([( + "src/Counter.sol".into(), + "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Counter {\n uint256 public number;\n\n function setNumber(uint256 newNumber) public {\n number = newNumber;\n }\n\n function increment() public {\n number++;\n }\n}\n".into(), + )]), + compiler_settings: json!({"evmVersion":"paris","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"*":["*"]}},"remappings":[],"viaIR":false}), + compilation_artifacts: CompilationArtifacts { + abi: Some(json!({"abi": "value"})), + devdoc: Some(json!({"devdoc": "value"})), + userdoc: Some(json!({"userdoc": "value"})), + storage_layout: Some(json!({"storage": "value"})), + sources: Some(BTreeMap::from([("src/Counter.sol".into(), SourceId {id: 0})])) + }, + creation_code: vec![0x1, 0x2], + creation_code_artifacts: CreationCodeArtifacts { + source_map: Some(json!("source_map")), + link_references: Some(json!({"linkReferences": "value"})), + cbor_auxdata: Some(json!({"cborAuxdata": "value"})), + }, + runtime_code: vec![0x3, 0x4], + runtime_code_artifacts: RuntimeCodeArtifacts { + cbor_auxdata: Some(json!({"cborAuxdata": "value"})), + immutable_references: Some(json!({"immutableReferences": "value"})), + link_references: Some(json!({"linkReferences": "value"})), + source_map: Some(json!("source_map")), + }, + } +} + +async fn insert_contract_deployment(database_connection: &DatabaseConnection) -> Uuid { + let contract_deployment = InsertContractDeployment::Regular { + chain_id: 10, + address: decode_hex("0x8FbB39A5a79aeCE03c8f13ccEE0b96C128ec1a67").unwrap(), + transaction_hash: decode_hex( + "0xf4042e19c445551d1059ad3856f83383c48699367cfb3e0edeccd26002dd2292", + ) + .unwrap(), + block_number: 127387809, + transaction_index: 16, + deployer: decode_hex("0x1F98431c8aD98523631AE4a59f267346ea31F984").unwrap(), + creation_code: vec![0x1, 0x2], + runtime_code: vec![0x3, 0x4], + }; + + verifier_alliance_database::insert_contract_deployment(database_connection, contract_deployment) + .await + .expect("error while inserting contract deployment") + .id +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/constructor_arguments.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/constructor_arguments.json new file mode 100644 index 000000000..17c3be32d --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/constructor_arguments.json @@ -0,0 +1,82 @@ +{ + "chain_id": "11155111", + "address": "0x664EEA330e41684EFE308014A4Ba358Bc079a853", + "transaction_hash": "0x8254ff650a3a4fae6ac905cad29c6ba81c7308c75f4d5d7526cd12eff73c0d98", + "block_number": "7108951", + "transaction_index": "27", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b506040516101e93803806101e98339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b610133806100b66000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c634300081200330000000000000000000000000000000000000000000000000000000000003039", + "deployed_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c63430008120033", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b506040516101e93803806101e98339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b610133806100b66000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c63430008120033", + "compiled_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n constructor(uint256 num) {\n number = num;\n }\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":4,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "141:262:0:-:0;;;192:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;236:3;227:6;:12;;;;192:54;141:262;;88:117:1;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:143::-;602:5;633:6;627:13;618:22;;649:33;676:5;649:33;:::i;:::-;545:143;;;;:::o;694:351::-;764:6;813:2;801:9;792:7;788:23;784:32;781:119;;;819:79;;:::i;:::-;781:119;939:1;964:64;1020:7;1011:6;1000:9;996:22;964:64;:::i;:::-;954:74;;910:128;694:351;;;;:::o;141:262:0:-;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 436, + "value": "0xa2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "141:262:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;337:64;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;164:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;337:64;391:3;382:6;:12;;;;337:64;:::o;164:21::-;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 254, + "value": "0xa2646970667358221220dd712ec4cb31d63cd32d3152e52e890b087769e9e4d6746844608039b5015d6a64736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": true, + "creation_values": { + "constructorArguments": "0x0000000000000000000000000000000000000000000000000000000000003039" + }, + "creation_transformations": [ + { + "type": "insert", + "reason": "constructorArguments", + "offset": 489 + } + ], + + "runtime_match": true, + "runtime_metadata_match": true, + "runtime_values": {}, + "runtime_transformations": [] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/full_match.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/full_match.json new file mode 100644 index 000000000..5087a88c6 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/full_match.json @@ -0,0 +1,74 @@ +{ + "chain_id": "11155111", + "address": "0xa851c68517290a357ec974D0a00A2f832322DdbA", + "transaction_hash": "0x1c92eea5fc29ab6e01ed0d76e8912c3c3a6dc5d2ecd64c076e69d07e6fed50f2", + "block_number": "7118016", + "transaction_index": "34", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b50610133806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + "deployed_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b50610133806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + "compiled_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":4,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "141:202:0:-:0;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 286, + "value": "0xa26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "141:202:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;277:64;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;164:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;277:64;331:3;322:6;:12;;;;277:64;:::o;164:21::-;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 254, + "value": "0xa26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": true, + "creation_values": {}, + "creation_transformations": [], + + "runtime_match": true, + "runtime_metadata_match": true, + "runtime_values": {}, + "runtime_transformations": [] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/immutables.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/immutables.json new file mode 100644 index 000000000..d0275b772 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/immutables.json @@ -0,0 +1,85 @@ +{ + "chain_id": "11155111", + "address": "0xe2c3685fD385077504A389A0Fd569Fab7E54dB7d", + "transaction_hash": "0x0e14052a4172a0adf1dc83d90b3b757539890af06665f2ecfaaf80790a697da0", + "block_number": "7118024", + "transaction_index": "49", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x60a0604052606460809081525034801561001857600080fd5b5060805161019a610033600039600060b0015261019a6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a146100625780639fe44c4a14610080575b600080fd5b610060600480360381019061005b919061010d565b61009e565b005b61006a6100a8565b6040516100779190610149565b60405180910390f35b6100886100ae565b6040516100959190610149565b60405180910390f35b8060008190555050565b60005481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080fd5b6000819050919050565b6100ea816100d7565b81146100f557600080fd5b50565b600081359050610107816100e1565b92915050565b600060208284031215610123576101226100d2565b5b6000610131848285016100f8565b91505092915050565b610143816100d7565b82525050565b600060208201905061015e600083018461013a565b9291505056fea26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033", + "deployed_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a146100625780639fe44c4a14610080575b600080fd5b610060600480360381019061005b919061010d565b61009e565b005b61006a6100a8565b6040516100779190610149565b60405180910390f35b6100886100ae565b6040516100959190610149565b60405180910390f35b8060008190555050565b60005481565b7f000000000000000000000000000000000000000000000000000000000000006481565b600080fd5b6000819050919050565b6100ea816100d7565b81146100f557600080fd5b50565b600081359050610107816100e1565b92915050565b600060208284031215610123576101226100d2565b5b6000610131848285016100f8565b91505092915050565b610143816100d7565b82525050565b600060208201905061015e600083018461013a565b9291505056fea26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033", + + "compiled_creation_code": "0x60a0604052606460809081525034801561001857600080fd5b5060805161019a610033600039600060b0015261019a6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a146100625780639fe44c4a14610080575b600080fd5b610060600480360381019061005b919061010d565b61009e565b005b61006a6100a8565b6040516100779190610149565b60405180910390f35b6100886100ae565b6040516100959190610149565b60405180910390f35b8060008190555050565b60005481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080fd5b6000819050919050565b6100ea816100d7565b81146100f557600080fd5b50565b600081359050610107816100e1565b92915050565b600060208284031215610123576101226100d2565b5b6000610131848285016100f8565b91505092915050565b610143816100d7565b82525050565b600060208201905061015e600083018461013a565b9291505056fea26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033", + "compiled_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a146100625780639fe44c4a14610080575b600080fd5b610060600480360381019061005b919061010d565b61009e565b005b61006a6100a8565b6040516100779190610149565b60405180910390f35b6100886100ae565b6040516100959190610149565b60405180910390f35b8060008190555050565b60005481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080fd5b6000819050919050565b6100ea816100d7565b81146100f557600080fd5b50565b600081359050610107816100e1565b92915050565b600060208284031215610123576101226100d2565b5b6000610131848285016100f8565b91505092915050565b610143816100d7565b82525050565b600060208201905061015e600083018461013a565b9291505056fea26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n uint256 public immutable imm_number = 100;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[],"name":"imm_number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":4,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "141:250:0:-:0;;;230:3;192:41;;;;;141:250;;;;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 408, + "value": "0xa26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {"7":[{"length":32,"start":176}]}, + "linkReferences": {}, + "sourceMap": "141:250:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;325:64;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;164:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;192:41;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;325:64;379:3;370:6;:12;;;;325:64;:::o;164:21::-;;;;:::o;192:41::-;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 357, + "value": "0xa26469706673582212205fff17b2676425e48225435ac15579ccae1af038ff8ffb334fc372526b94722664736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": true, + "creation_values": {}, + "creation_transformations": [], + + "runtime_match": true, + "runtime_metadata_match": true, + "runtime_values": { + "immutables": { + "7": "0x0000000000000000000000000000000000000000000000000000000000000064" + } + }, + "runtime_transformations": [ + { + "type": "replace", + "reason": "immutable", + "offset": 176, + "id": "7" + } + ] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_linked_by_compiler.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_linked_by_compiler.json new file mode 100644 index 000000000..18777e8af --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_linked_by_compiler.json @@ -0,0 +1,80 @@ +{ + "_comment": "Libraries have been linked using compiler settings. The placeholders are already replaced inside the compiled bytecode, and no link references provided", + + "chain_id": "11155111", + "address": "0xc586D55a9fcDCA43dE7ebd097DEc950D50559Bbd", + "transaction_hash": "0x7a980a5a51804cccd75e3b8329c3ce5213d603f66b297cee908a7cbd2151241a", + "block_number": "7118254", + "transaction_index": "26", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b50610249806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033", + "deployed_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b50610249806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033", + "compiled_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\nlibrary Journal {\n function record(mapping(uint256 => uint256) storage journal, uint256 num) public {\n journal[block.number] = num;\n }\n}\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n mapping(uint256 => uint256) public journal;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n Journal.record(journal, num);\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": { + "contracts/1_Storage.sol": { + "Journal": "0x7d53f102f4d4aa014db4e10d6deec2009b3cda6b" + } + }, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"journal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":22,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"},{"astId":26,"contract":"contracts/1_Storage.sol:Storage","label":"journal","offset":0,"slot":"1","type":"t_mapping(t_uint256,t_uint256)"}],"types":{"t_mapping(t_uint256,t_uint256)":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => uint256)","numberOfBytes":"32","value":"t_uint256"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "292:289:0:-:0;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 564, + "value": "0xa2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "292:289:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;477:102;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;315:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;343:42;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;477:102;531:3;522:6;:12;;;;544:7;:14;559:7;568:3;544:28;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;477:102;:::o;315:21::-;;;;:::o;343:42::-;;;;;;;;;;;;;;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o;1377:132::-;1497:5;1492:3;1485:18;1377:132;;:::o;1515:126::-;1610:24;1628:5;1610:24;:::i;:::-;1605:3;1598:37;1515:126;;:::o;1647:406::-;1801:4;1839:2;1828:9;1824:18;1816:26;;1852:104;1953:1;1942:9;1938:17;1929:6;1852:104;:::i;:::-;1966:80;2042:2;2031:9;2027:18;2018:6;1966:80;:::i;:::-;1647:406;;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 532, + "value": "0xa2646970667358221220a89051eba557a7a71a7afa4c5011918b95b51d314ed350221cb7a2f34703340364736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": true, + "creation_values": {}, + "creation_transformations": [], + + "runtime_match": true, + "runtime_metadata_match": true, + "runtime_values": {}, + "runtime_transformations": [] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_manually_linked.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_manually_linked.json new file mode 100644 index 000000000..8044aa65d --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/libraries_manually_linked.json @@ -0,0 +1,98 @@ +{ + "_comment": "Libraries have been linked manually instead of using compiler settings. Placeholders are replaced with zero addresses", + + "chain_id": "11155111", + "address": "0x90aA6A3f6A111382ea3f2b909b1bE61F5CBAdFEd", + "transaction_hash": "0x977a73ee3ed5ee36bd794615311ba5a487d96db4d1e0e87ac3c9825e9be787f7", + "block_number": "7118262", + "transaction_index": "40", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b50610249806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033", + "deployed_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550737d53f102f4d4aa014db4e10d6deec2009b3cda6b632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b50610249806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550730000000000000000000000000000000000000000632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033", + "compiled_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80636057361d146100465780638381f58a14610062578063e2e2a85a14610080575b600080fd5b610060600480360381019061005b919061017d565b6100b0565b005b61006a610124565b60405161007791906101b9565b60405180910390f35b61009a6004803603810190610095919061017d565b61012a565b6040516100a791906101b9565b60405180910390f35b80600081905550730000000000000000000000000000000000000000632be59dd56001836040518363ffffffff1660e01b81526004016100f19291906101ea565b60006040518083038186803b15801561010957600080fd5b505af415801561011d573d6000803e3d6000fd5b5050505050565b60005481565b60016020528060005260406000206000915090505481565b600080fd5b6000819050919050565b61015a81610147565b811461016557600080fd5b50565b60008135905061017781610151565b92915050565b60006020828403121561019357610192610142565b5b60006101a184828501610168565b91505092915050565b6101b381610147565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b8082525050565b6101e481610147565b82525050565b60006040820190506101ff60008301856101d4565b61020c60208301846101db565b939250505056fea26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\nlibrary Journal {\n function record(mapping(uint256 => uint256) storage journal, uint256 num) public {\n journal[block.number] = num;\n }\n}\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n mapping(uint256 => uint256) public journal;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n Journal.record(journal, num);\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"journal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":22,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"},{"astId":26,"contract":"contracts/1_Storage.sol:Storage","label":"journal","offset":0,"slot":"1","type":"t_mapping(t_uint256,t_uint256)"}],"types":{"t_mapping(t_uint256,t_uint256)":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => uint256)","numberOfBytes":"32","value":"t_uint256"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {"contracts/1_Storage.sol":{"Journal":[{"length":20,"start":217}]}}, + "sourceMap": "292:289:0:-:0;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 564, + "value": "0xa26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {"contracts/1_Storage.sol":{"Journal":[{"length":20,"start":185}]}}, + "sourceMap": "292:289:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;477:102;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;315:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;343:42;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;477:102;531:3;522:6;:12;;;;544:7;:14;559:7;568:3;544:28;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;477:102;:::o;315:21::-;;;;:::o;343:42::-;;;;;;;;;;;;;;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o;1377:132::-;1497:5;1492:3;1485:18;1377:132;;:::o;1515:126::-;1610:24;1628:5;1610:24;:::i;:::-;1605:3;1598:37;1515:126;;:::o;1647:406::-;1801:4;1839:2;1828:9;1824:18;1816:26;;1852:104;1953:1;1942:9;1938:17;1929:6;1852:104;:::i;:::-;1966:80;2042:2;2031:9;2027:18;2018:6;1966:80;:::i;:::-;1647:406;;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 532, + "value": "0xa26469706673582212205d40d1517b560d915e1b7c005887b93fcce9ec65c0a38a80ee147739551bdd7264736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": true, + "creation_values": { + "libraries": { + "contracts/1_Storage.sol:Journal": "0x7d53f102f4d4aa014db4e10d6deec2009b3cda6b" + } + }, + "creation_transformations": [ + { + "type": "replace", + "reason": "library", + "offset": 217, + "id": "contracts/1_Storage.sol:Journal" + } + ], + + "runtime_match": true, + "runtime_metadata_match": true, + "runtime_values": { + "libraries": { + "contracts/1_Storage.sol:Journal": "0x7d53f102f4d4aa014db4e10d6deec2009b3cda6b" + } + }, + "runtime_transformations": [ + { + "type": "replace", + "reason": "library", + "offset": 185, + "id": "contracts/1_Storage.sol:Journal" + } + ] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/metadata_hash_absent.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/metadata_hash_absent.json new file mode 100644 index 000000000..8d77698a3 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/metadata_hash_absent.json @@ -0,0 +1,77 @@ +{ + "chain_id": "11155111", + "address": "0x8Baf31AAb52Dca9D17f8BDeB06Da5FB3f2520D4F", + "transaction_hash": "0xce2eb694f6a6b1016ada043c9a796a254132d664ca82d6f1f6b1be4e45222cac", + "block_number": "7118270", + "transaction_index": "36", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b5061010a806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea164736f6c6343000812000a", + "deployed_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea164736f6c6343000812000a", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b5061010a806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea164736f6c6343000812000a", + "compiled_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea164736f6c6343000812000a", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "metadata": { + "bytecodeHash": "none" + }, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":4,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "141:202:0:-:0;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 286, + "value": "0xa164736f6c6343000812000a" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "141:202:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;277:64;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;164:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;277:64;331:3;322:6;:12;;;;277:64;:::o;164:21::-;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 254, + "value": "0xa164736f6c6343000812000a" + } + } + }, + + "creation_match": true, + "creation_metadata_match": false, + "creation_values": {}, + "creation_transformations": [], + + "runtime_match": true, + "runtime_metadata_match": false, + "runtime_values": {}, + "runtime_transformations": [] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match.json new file mode 100644 index 000000000..6be26bc8b --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match.json @@ -0,0 +1,98 @@ +{ + "_comment": "Argument `store.num` has been updated to `store.modified_num` to change the metadata hash", + + "chain_id": "11155111", + "address": "0x1052623FD0425d216A7c2FB466f6DbF216323282", + "transaction_hash": "0x48d7e8d4853f1001e7221ab49c01c62380d1a807d138f0c419dde45093472d92", + "block_number": "7118274", + "transaction_index": "18", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x608060405234801561001057600080fd5b50610133806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + "deployed_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033", + + "compiled_creation_code": "0x608060405234801561001057600080fd5b50610133806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212203863ce629eb61798cd34ba5d73d729ef1f86d2529ee1bdfc20e7eda860c4260564736f6c63430008120033", + "compiled_runtime_code": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d1460375780638381f58a14604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea26469706673582212203863ce629eb61798cd34ba5d73d729ef1f86d2529ee1bdfc20e7eda860c4260564736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n /**\n * @dev Store value in variable\n * @param modified_num value to store\n */\n function store(uint256 modified_num) public {\n number = modified_num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"modified_num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"modified_num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":4,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "141:229:0:-:0;;;;;;;;;;;;;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 286, + "value": "0xa26469706673582212203863ce629eb61798cd34ba5d73d729ef1f86d2529ee1bdfc20e7eda860c4260564736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "141:229:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;286:82;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;164:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;286:82;349:12;340:6;:21;;;;286:82;:::o;164:21::-;;;;:::o;88:117:1:-;197:1;194;187:12;334:77;371:7;400:5;389:16;;334:77;;;:::o;417:122::-;490:24;508:5;490:24;:::i;:::-;483:5;480:35;470:63;;529:1;526;519:12;470:63;417:122;:::o;545:139::-;591:5;629:6;616:20;607:29;;645:33;672:5;645:33;:::i;:::-;545:139;;;;:::o;690:329::-;749:6;798:2;786:9;777:7;773:23;769:32;766:119;;;804:79;;:::i;:::-;766:119;924:1;949:53;994:7;985:6;974:9;970:22;949:53;:::i;:::-;939:63;;895:117;690:329;;;;:::o;1025:118::-;1112:24;1130:5;1112:24;:::i;:::-;1107:3;1100:37;1025:118;;:::o;1149:222::-;1242:4;1280:2;1269:9;1265:18;1257:26;;1293:71;1361:1;1350:9;1346:17;1337:6;1293:71;:::i;:::-;1149:222;;;;:::o", + "cborAuxdata": { + "1": { + "offset": 254, + "value": "0xa26469706673582212203863ce629eb61798cd34ba5d73d729ef1f86d2529ee1bdfc20e7eda860c4260564736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": false, + "creation_values": { + "cborAuxdata": { + "1": "0xa26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033" + } + }, + "creation_transformations": [ + { + "type": "replace", + "reason": "cborAuxdata", + "offset": 286, + "id": "1" + } + ], + + "runtime_match": true, + "runtime_metadata_match": false, + "runtime_values": { + "cborAuxdata": { + "1": "0xa26469706673582212204ac0ce5f82b26331fa3e9ae959291a55624ffaf90fcd509deafcc21a5f1da21e64736f6c63430008120033" + } + }, + "runtime_transformations": [ + { + "type": "replace", + "reason": "cborAuxdata", + "offset": 254, + "id": "1" + } + ] +} diff --git a/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match_double_auxdata.json b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match_double_auxdata.json new file mode 100644 index 000000000..0ec3161a1 --- /dev/null +++ b/eth-bytecode-db/verifier-alliance-database/tests/test_cases/partial_match_double_auxdata.json @@ -0,0 +1,107 @@ +{ + "chain_id": "11155111", + "address": "0x383eEaD9Ceeb888827d40D9f194882B36590378a", + "transaction_hash": "0x097e11c77a37c93e7fa38d9a883fad1dbf0572b6785b303b1bffeebdbed75dff", + "block_number": "7118283", + "transaction_index": "17", + "deployer": "0x8dB94A1C4b68c4d44E6d2cFEE59a9A960198dc64", + + "deployed_creation_code": "0x60806040526040518060200161001490610049565b6020820181038252601f19601f820116604052506001908161003691906102a5565b5034801561004357600080fd5b50610377565b605c8061069c83390190565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806100d657607f821691505b6020821081036100e9576100e861008f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610114565b61015b8683610114565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101a261019d61019884610173565b61017d565b610173565b9050919050565b6000819050919050565b6101bc83610187565b6101d06101c8826101a9565b848454610121565b825550505050565b600090565b6101e56101d8565b6101f08184846101b3565b505050565b5b81811015610214576102096000826101dd565b6001810190506101f6565b5050565b601f8211156102595761022a816100ef565b61023384610104565b81016020851015610242578190505b61025661024e85610104565b8301826101f5565b50505b505050565b600082821c905092915050565b600061027c6000198460080261025e565b1980831691505092915050565b6000610295838361026b565b9150826002028217905092915050565b6102ae82610055565b67ffffffffffffffff8111156102c7576102c6610060565b5b6102d182546100be565b6102dc828285610218565b600060209050601f83116001811461030f57600084156102fd578287015190505b6103078582610289565b86555061036f565b601f19841661031d866100ef565b60005b8281101561034557848901518255600182019150602085019450602081019050610320565b86831015610362578489015161035e601f89168261026b565b8355505b6001600288020188555050505b505050505050565b610316806103866000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806324c12bf6146100465780636057361d146100645780638381f58a14610080575b600080fd5b61004e61009e565b60405161005b91906101cc565b60405180910390f35b61007e60048036038101906100799190610229565b61012c565b005b610088610136565b6040516100959190610265565b60405180910390f35b600180546100ab906102af565b80601f01602080910402602001604051908101604052809291908181526020018280546100d7906102af565b80156101245780601f106100f957610100808354040283529160200191610124565b820191906000526020600020905b81548152906001019060200180831161010757829003601f168201915b505050505081565b8060008190555050565b60005481565b600081519050919050565b600082825260208201905092915050565b60005b8381101561017657808201518184015260208101905061015b565b60008484015250505050565b6000601f19601f8301169050919050565b600061019e8261013c565b6101a88185610147565b93506101b8818560208601610158565b6101c181610182565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600080fd5b6000819050919050565b610206816101f3565b811461021157600080fd5b50565b600081359050610223816101fd565b92915050565b60006020828403121561023f5761023e6101ee565b5b600061024d84828501610214565b91505092915050565b61025f816101f3565b82525050565b600060208201905061027a6000830184610256565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806102c757607f821691505b6020821081036102da576102d9610280565b5b5091905056fea2646970667358221220bc2c6d72c52842d4077bb24c307576e44a078831aaa16da6611ef342fd052ec764736f6c634300081200336080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220f13d144a826a3f18798a534a4b10029a3284d9f4620ccc79750cdc48442cdaad64736f6c63430008120033", + "deployed_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806324c12bf6146100465780636057361d146100645780638381f58a14610080575b600080fd5b61004e61009e565b60405161005b91906101cc565b60405180910390f35b61007e60048036038101906100799190610229565b61012c565b005b610088610136565b6040516100959190610265565b60405180910390f35b600180546100ab906102af565b80601f01602080910402602001604051908101604052809291908181526020018280546100d7906102af565b80156101245780601f106100f957610100808354040283529160200191610124565b820191906000526020600020905b81548152906001019060200180831161010757829003601f168201915b505050505081565b8060008190555050565b60005481565b600081519050919050565b600082825260208201905092915050565b60005b8381101561017657808201518184015260208101905061015b565b60008484015250505050565b6000601f19601f8301169050919050565b600061019e8261013c565b6101a88185610147565b93506101b8818560208601610158565b6101c181610182565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600080fd5b6000819050919050565b610206816101f3565b811461021157600080fd5b50565b600081359050610223816101fd565b92915050565b60006020828403121561023f5761023e6101ee565b5b600061024d84828501610214565b91505092915050565b61025f816101f3565b82525050565b600060208201905061027a6000830184610256565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806102c757607f821691505b6020821081036102da576102d9610280565b5b5091905056fea2646970667358221220bc2c6d72c52842d4077bb24c307576e44a078831aaa16da6611ef342fd052ec764736f6c63430008120033", + + "compiled_creation_code": "0x60806040526040518060200161001490610049565b6020820181038252601f19601f820116604052506001908161003691906102a5565b5034801561004357600080fd5b50610377565b605c8061069c83390190565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806100d657607f821691505b6020821081036100e9576100e861008f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026101517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610114565b61015b8683610114565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006101a261019d61019884610173565b61017d565b610173565b9050919050565b6000819050919050565b6101bc83610187565b6101d06101c8826101a9565b848454610121565b825550505050565b600090565b6101e56101d8565b6101f08184846101b3565b505050565b5b81811015610214576102096000826101dd565b6001810190506101f6565b5050565b601f8211156102595761022a816100ef565b61023384610104565b81016020851015610242578190505b61025661024e85610104565b8301826101f5565b50505b505050565b600082821c905092915050565b600061027c6000198460080261025e565b1980831691505092915050565b6000610295838361026b565b9150826002028217905092915050565b6102ae82610055565b67ffffffffffffffff8111156102c7576102c6610060565b5b6102d182546100be565b6102dc828285610218565b600060209050601f83116001811461030f57600084156102fd578287015190505b6103078582610289565b86555061036f565b601f19841661031d866100ef565b60005b8281101561034557848901518255600182019150602085019450602081019050610320565b86831015610362578489015161035e601f89168261026b565b8355505b6001600288020188555050505b505050505050565b610316806103866000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806324c12bf6146100465780636057361d146100645780638381f58a14610080575b600080fd5b61004e61009e565b60405161005b91906101cc565b60405180910390f35b61007e60048036038101906100799190610229565b61012c565b005b610088610136565b6040516100959190610265565b60405180910390f35b600180546100ab906102af565b80601f01602080910402602001604051908101604052809291908181526020018280546100d7906102af565b80156101245780601f106100f957610100808354040283529160200191610124565b820191906000526020600020905b81548152906001019060200180831161010757829003601f168201915b505050505081565b8060008190555050565b60005481565b600081519050919050565b600082825260208201905092915050565b60005b8381101561017657808201518184015260208101905061015b565b60008484015250505050565b6000601f19601f8301169050919050565b600061019e8261013c565b6101a88185610147565b93506101b8818560208601610158565b6101c181610182565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600080fd5b6000819050919050565b610206816101f3565b811461021157600080fd5b50565b600081359050610223816101fd565b92915050565b60006020828403121561023f5761023e6101ee565b5b600061024d84828501610214565b91505092915050565b61025f816101f3565b82525050565b600060208201905061027a6000830184610256565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806102c757607f821691505b6020821081036102da576102d9610280565b5b5091905056fea264697066735822122005d1b64ca59de3c6d96eee72b6fef65fc503bfbf8d9719fb047fafce2ebdc29764736f6c634300081200336080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220aebf48746b808da25305449bba6945baacf1c2185dfcc58a94b1506b8b5a6dfa64736f6c63430008120033", + "compiled_runtime_code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806324c12bf6146100465780636057361d146100645780638381f58a14610080575b600080fd5b61004e61009e565b60405161005b91906101cc565b60405180910390f35b61007e60048036038101906100799190610229565b61012c565b005b610088610136565b6040516100959190610265565b60405180910390f35b600180546100ab906102af565b80601f01602080910402602001604051908101604052809291908181526020018280546100d7906102af565b80156101245780601f106100f957610100808354040283529160200191610124565b820191906000526020600020905b81548152906001019060200180831161010757829003601f168201915b505050505081565b8060008190555050565b60005481565b600081519050919050565b600082825260208201905092915050565b60005b8381101561017657808201518184015260208101905061015b565b60008484015250505050565b6000601f19601f8301169050919050565b600061019e8261013c565b6101a88185610147565b93506101b8818560208601610158565b6101c181610182565b840191505092915050565b600060208201905081810360008301526101e68184610193565b905092915050565b600080fd5b6000819050919050565b610206816101f3565b811461021157600080fd5b50565b600081359050610223816101fd565b92915050565b60006020828403121561023f5761023e6101ee565b5b600061024d84828501610214565b91505092915050565b61025f816101f3565b82525050565b600060208201905061027a6000830184610256565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806102c757607f821691505b6020821081036102da576102d9610280565b5b5091905056fea264697066735822122005d1b64ca59de3c6d96eee72b6fef65fc503bfbf8d9719fb047fafce2ebdc29764736f6c63430008120033", + "compiler": "solc", + "version": "v0.8.18+commit.87f61d96", + "language": "solidity", + "name": "Storage", + "fully_qualified_name": "contracts/1_Storage.sol:Storage", + "sources": { + "contracts/1_Storage.sol": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\ncontract A {}\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n uint256 public number;\n\n // Comment to update metadata hash\n bytes public code = type(A).creationCode;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n}" + }, + "compiler_settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "libraries": {}, + "outputSelection": { + "*": { + "*": [ + "*" + ] + } + } + }, + "compilation_artifacts": { + "abi": [{"inputs":[],"name":"code","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}], + "devdoc": {"details":"Store & retrieve value in a variable","kind":"dev","methods":{"store(uint256)":{"details":"Store value in variable","params":{"num":"value to store"}}},"title":"Storage","version":1}, + "userdoc": {"kind":"user","methods":{},"version":1}, + "storageLayout": {"storage":[{"astId":5,"contract":"contracts/1_Storage.sol:Storage","label":"number","offset":0,"slot":"0","type":"t_uint256"},{"astId":11,"contract":"contracts/1_Storage.sol:Storage","label":"code","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}, + "sources": {"contracts/1_Storage.sol": {"id": 0} } + }, + "creation_code_artifacts": { + "linkReferences": {}, + "sourceMap": "156:288:0:-:0;;;266:20;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;246:40;;;;;;;:::i;:::-;;156:288;;;;;;;;;;;;;;;;;;;;:::o;7:98:1:-;58:6;92:5;86:12;76:22;;7:98;;;:::o;111:180::-;159:77;156:1;149:88;256:4;253:1;246:15;280:4;277:1;270:15;297:180;345:77;342:1;335:88;442:4;439:1;432:15;466:4;463:1;456:15;483:320;527:6;564:1;558:4;554:12;544:22;;611:1;605:4;601:12;632:18;622:81;;688:4;680:6;676:17;666:27;;622:81;750:2;742:6;739:14;719:18;716:38;713:84;;769:18;;:::i;:::-;713:84;534:269;483:320;;;:::o;809:140::-;857:4;880:3;872:11;;903:3;900:1;893:14;937:4;934:1;924:18;916:26;;809:140;;;:::o;955:93::-;992:6;1039:2;1034;1027:5;1023:14;1019:23;1009:33;;955:93;;;:::o;1054:107::-;1098:8;1148:5;1142:4;1138:16;1117:37;;1054:107;;;;:::o;1167:393::-;1236:6;1286:1;1274:10;1270:18;1309:97;1339:66;1328:9;1309:97;:::i;:::-;1427:39;1457:8;1446:9;1427:39;:::i;:::-;1415:51;;1499:4;1495:9;1488:5;1484:21;1475:30;;1548:4;1538:8;1534:19;1527:5;1524:30;1514:40;;1243:317;;1167:393;;;;;:::o;1566:77::-;1603:7;1632:5;1621:16;;1566:77;;;:::o;1649:60::-;1677:3;1698:5;1691:12;;1649:60;;;:::o;1715:142::-;1765:9;1798:53;1816:34;1825:24;1843:5;1825:24;:::i;:::-;1816:34;:::i;:::-;1798:53;:::i;:::-;1785:66;;1715:142;;;:::o;1863:75::-;1906:3;1927:5;1920:12;;1863:75;;;:::o;1944:269::-;2054:39;2085:7;2054:39;:::i;:::-;2115:91;2164:41;2188:16;2164:41;:::i;:::-;2156:6;2149:4;2143:11;2115:91;:::i;:::-;2109:4;2102:105;2020:193;1944:269;;;:::o;2219:73::-;2264:3;2219:73;:::o;2298:189::-;2375:32;;:::i;:::-;2416:65;2474:6;2466;2460:4;2416:65;:::i;:::-;2351:136;2298:189;;:::o;2493:186::-;2553:120;2570:3;2563:5;2560:14;2553:120;;;2624:39;2661:1;2654:5;2624:39;:::i;:::-;2597:1;2590:5;2586:13;2577:22;;2553:120;;;2493:186;;:::o;2685:541::-;2785:2;2780:3;2777:11;2774:445;;;2819:37;2850:5;2819:37;:::i;:::-;2902:29;2920:10;2902:29;:::i;:::-;2892:8;2888:44;3085:2;3073:10;3070:18;3067:49;;;3106:8;3091:23;;3067:49;3129:80;3185:22;3203:3;3185:22;:::i;:::-;3175:8;3171:37;3158:11;3129:80;:::i;:::-;2789:430;;2774:445;2685:541;;;:::o;3232:117::-;3286:8;3336:5;3330:4;3326:16;3305:37;;3232:117;;;;:::o;3355:169::-;3399:6;3432:51;3480:1;3476:6;3468:5;3465:1;3461:13;3432:51;:::i;:::-;3428:56;3513:4;3507;3503:15;3493:25;;3406:118;3355:169;;;;:::o;3529:295::-;3605:4;3751:29;3776:3;3770:4;3751:29;:::i;:::-;3743:37;;3813:3;3810:1;3806:11;3800:4;3797:21;3789:29;;3529:295;;;;:::o;3829:1390::-;3944:36;3976:3;3944:36;:::i;:::-;4045:18;4037:6;4034:30;4031:56;;;4067:18;;:::i;:::-;4031:56;4111:38;4143:4;4137:11;4111:38;:::i;:::-;4196:66;4255:6;4247;4241:4;4196:66;:::i;:::-;4289:1;4313:4;4300:17;;4345:2;4337:6;4334:14;4362:1;4357:617;;;;5018:1;5035:6;5032:77;;;5084:9;5079:3;5075:19;5069:26;5060:35;;5032:77;5135:67;5195:6;5188:5;5135:67;:::i;:::-;5129:4;5122:81;4991:222;4327:886;;4357:617;4409:4;4405:9;4397:6;4393:22;4443:36;4474:4;4443:36;:::i;:::-;4501:1;4515:208;4529:7;4526:1;4523:14;4515:208;;;4608:9;4603:3;4599:19;4593:26;4585:6;4578:42;4659:1;4651:6;4647:14;4637:24;;4706:2;4695:9;4691:18;4678:31;;4552:4;4549:1;4545:12;4540:17;;4515:208;;;4751:6;4742:7;4739:19;4736:179;;;4809:9;4804:3;4800:19;4794:26;4852:48;4894:4;4886:6;4882:17;4871:9;4852:48;:::i;:::-;4844:6;4837:64;4759:156;4736:179;4961:1;4957;4949:6;4945:14;4941:22;4935:4;4928:36;4364:610;;;4327:886;;3919:1300;;;3829:1390;;:::o;156:288:0:-;;;;;;;", + "cborAuxdata": { + "1": { + "offset": 1639, + "value": "0xa264697066735822122005d1b64ca59de3c6d96eee72b6fef65fc503bfbf8d9719fb047fafce2ebdc29764736f6c63430008120033" + }, + "2": { + "offset": 1731, + "value": "0xa2646970667358221220aebf48746b808da25305449bba6945baacf1c2185dfcc58a94b1506b8b5a6dfa64736f6c63430008120033" + } + } + }, + "runtime_code_artifacts": { + "immutableReferences": {}, + "linkReferences": {}, + "sourceMap": "156:288:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;246:40;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;378:64;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;179:21;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;246:40;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;378:64::-;432:3;423:6;:12;;;;378:64;:::o;179:21::-;;;;:::o;7:98:1:-;58:6;92:5;86:12;76:22;;7:98;;;:::o;111:168::-;194:11;228:6;223:3;216:19;268:4;263:3;259:14;244:29;;111:168;;;;:::o;285:246::-;366:1;376:113;390:6;387:1;384:13;376:113;;;475:1;470:3;466:11;460:18;456:1;451:3;447:11;440:39;412:2;409:1;405:10;400:15;;376:113;;;523:1;514:6;509:3;505:16;498:27;347:184;285:246;;;:::o;537:102::-;578:6;629:2;625:7;620:2;613:5;609:14;605:28;595:38;;537:102;;;:::o;645:373::-;731:3;759:38;791:5;759:38;:::i;:::-;813:70;876:6;871:3;813:70;:::i;:::-;806:77;;892:65;950:6;945:3;938:4;931:5;927:16;892:65;:::i;:::-;982:29;1004:6;982:29;:::i;:::-;977:3;973:39;966:46;;735:283;645:373;;;;:::o;1024:309::-;1135:4;1173:2;1162:9;1158:18;1150:26;;1222:9;1216:4;1212:20;1208:1;1197:9;1193:17;1186:47;1250:76;1321:4;1312:6;1250:76;:::i;:::-;1242:84;;1024:309;;;;:::o;1420:117::-;1529:1;1526;1519:12;1666:77;1703:7;1732:5;1721:16;;1666:77;;;:::o;1749:122::-;1822:24;1840:5;1822:24;:::i;:::-;1815:5;1812:35;1802:63;;1861:1;1858;1851:12;1802:63;1749:122;:::o;1877:139::-;1923:5;1961:6;1948:20;1939:29;;1977:33;2004:5;1977:33;:::i;:::-;1877:139;;;;:::o;2022:329::-;2081:6;2130:2;2118:9;2109:7;2105:23;2101:32;2098:119;;;2136:79;;:::i;:::-;2098:119;2256:1;2281:53;2326:7;2317:6;2306:9;2302:22;2281:53;:::i;:::-;2271:63;;2227:117;2022:329;;;;:::o;2357:118::-;2444:24;2462:5;2444:24;:::i;:::-;2439:3;2432:37;2357:118;;:::o;2481:222::-;2574:4;2612:2;2601:9;2597:18;2589:26;;2625:71;2693:1;2682:9;2678:17;2669:6;2625:71;:::i;:::-;2481:222;;;;:::o;2709:180::-;2757:77;2754:1;2747:88;2854:4;2851:1;2844:15;2878:4;2875:1;2868:15;2895:320;2939:6;2976:1;2970:4;2966:12;2956:22;;3023:1;3017:4;3013:12;3044:18;3034:81;;3100:4;3092:6;3088:17;3078:27;;3034:81;3162:2;3154:6;3151:14;3131:18;3128:38;3125:84;;3181:18;;:::i;:::-;3125:84;2946:269;2895:320;;;:::o", + "cborAuxdata": { + "1": { + "offset": 737, + "value": "0xa264697066735822122005d1b64ca59de3c6d96eee72b6fef65fc503bfbf8d9719fb047fafce2ebdc29764736f6c63430008120033" + } + } + }, + + "creation_match": true, + "creation_metadata_match": false, + "creation_values": { + "cborAuxdata": { + "1": "0xa2646970667358221220bc2c6d72c52842d4077bb24c307576e44a078831aaa16da6611ef342fd052ec764736f6c63430008120033", + "2": "0xa2646970667358221220f13d144a826a3f18798a534a4b10029a3284d9f4620ccc79750cdc48442cdaad64736f6c63430008120033" + } + }, + "creation_transformations": [ + { + "type": "replace", + "reason": "cborAuxdata", + "offset": 1639, + "id": "1" + }, + { + "type": "replace", + "reason": "cborAuxdata", + "offset": 1731, + "id": "2" + } + ], + + "runtime_match": true, + "runtime_metadata_match": false, + "runtime_values": { + "cborAuxdata": { + "1": "0xa2646970667358221220bc2c6d72c52842d4077bb24c307576e44a078831aaa16da6611ef342fd052ec764736f6c63430008120033" + } + }, + "runtime_transformations": [ + { + "type": "replace", + "reason": "cborAuxdata", + "offset": 737, + "id": "1" + } + ] +} diff --git a/libs/verification-common/Cargo.toml b/libs/verification-common/Cargo.toml index 3cd80cc78..2df5fb4a3 100644 --- a/libs/verification-common/Cargo.toml +++ b/libs/verification-common/Cargo.toml @@ -11,6 +11,7 @@ alloy-json-abi = "0.8" anyhow = "1.0" blockscout-display-bytes = "1.1.0" bytes = "1" +readonly = { version = "0.2.12" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_with = "3.8" diff --git a/libs/verification-common/src/verifier_alliance/compilation_artifacts.rs b/libs/verification-common/src/verifier_alliance/compilation_artifacts.rs index ec6a57f27..dcaa40a71 100644 --- a/libs/verification-common/src/verifier_alliance/compilation_artifacts.rs +++ b/libs/verification-common/src/verifier_alliance/compilation_artifacts.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; +use std::collections::BTreeMap; pub trait ToCompilationArtifacts { fn abi(&self) -> Option { @@ -31,17 +32,20 @@ impl ToCompilationArtifacts for &T { } } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SourceId { + pub id: u64, +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CompilationArtifacts { - #[serde(skip_serializing_if = "Option::is_none")] pub abi: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub devdoc: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub userdoc: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub storage_layout: Option, + pub sources: Option>, } impl From for CompilationArtifacts { @@ -51,6 +55,7 @@ impl From for CompilationArtifacts { devdoc: value.devdoc(), userdoc: value.userdoc(), storage_layout: value.storage_layout(), + sources: None, } } } diff --git a/libs/verification-common/src/verifier_alliance/creation_code_artifacts.rs b/libs/verification-common/src/verifier_alliance/creation_code_artifacts.rs index 1520aff12..3877a8075 100644 --- a/libs/verification-common/src/verifier_alliance/creation_code_artifacts.rs +++ b/libs/verification-common/src/verifier_alliance/creation_code_artifacts.rs @@ -28,11 +28,8 @@ impl ToCreationCodeArtifacts for &T { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CreationCodeArtifacts { - #[serde(skip_serializing_if = "Option::is_none")] pub source_map: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub link_references: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub cbor_auxdata: Option, } diff --git a/libs/verification-common/src/verifier_alliance/mod.rs b/libs/verification-common/src/verifier_alliance/mod.rs index adb38f75b..0070d14bb 100644 --- a/libs/verification-common/src/verifier_alliance/mod.rs +++ b/libs/verification-common/src/verifier_alliance/mod.rs @@ -6,7 +6,7 @@ mod verification_match; mod verification_match_transformations; mod verification_match_values; -pub use compilation_artifacts::{CompilationArtifacts, ToCompilationArtifacts}; +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, MatchType, MatchValues}; +pub use verification_match::{Match, MatchBuilder, MatchTransformation, MatchValues}; diff --git a/libs/verification-common/src/verifier_alliance/runtime_code_artifacts.rs b/libs/verification-common/src/verifier_alliance/runtime_code_artifacts.rs index 034a2b84f..75f10085f 100644 --- a/libs/verification-common/src/verifier_alliance/runtime_code_artifacts.rs +++ b/libs/verification-common/src/verifier_alliance/runtime_code_artifacts.rs @@ -34,13 +34,9 @@ impl ToRuntimeCodeArtifacts for &T { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RuntimeCodeArtifacts { - #[serde(skip_serializing_if = "Option::is_none")] pub cbor_auxdata: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub immutable_references: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub link_references: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub source_map: Option, } diff --git a/libs/verification-common/src/verifier_alliance/verification_match.rs b/libs/verification-common/src/verifier_alliance/verification_match.rs index 73c125e32..ef5a041bf 100644 --- a/libs/verification-common/src/verifier_alliance/verification_match.rs +++ b/libs/verification-common/src/verifier_alliance/verification_match.rs @@ -10,26 +10,10 @@ use alloy_dyn_abi::JsonAbiExt; use anyhow::Context; use bytes::Bytes; use serde::Deserialize; -use std::fmt::{Display, Formatter}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum MatchType { - Full, - Partial, -} - -impl Display for MatchType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - MatchType::Full => f.write_str("full"), - MatchType::Partial => f.write_str("partial"), - } - } -} #[derive(Clone, Debug, PartialEq, Eq)] pub struct Match { - pub r#type: MatchType, + pub metadata_match: bool, pub transformations: Vec, pub values: MatchValues, } @@ -90,13 +74,9 @@ impl<'a> MatchBuilder<'a> { if !self.invalid_constructor_arguments && self.deployed_code == self.compiled_code.as_slice() { - let match_type = if self.has_cbor_auxdata_transformation || !self.has_cbor_auxdata { - MatchType::Partial - } else { - MatchType::Full - }; + let metadata_match = self.has_cbor_auxdata && !self.has_cbor_auxdata_transformation; return Some(Match { - r#type: match_type, + metadata_match, transformations: self.transformations, values: self.values, }); diff --git a/libs/verification-common/src/verifier_alliance/verification_match_transformations.rs b/libs/verification-common/src/verifier_alliance/verification_match_transformations.rs index 006509870..7b36e7150 100644 --- a/libs/verification-common/src/verifier_alliance/verification_match_transformations.rs +++ b/libs/verification-common/src/verifier_alliance/verification_match_transformations.rs @@ -10,8 +10,8 @@ enum TransformationType { #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] enum TransformationReason { - Auxdata, - Constructor, + CborAuxdata, + ConstructorArguments, Immutable, Library, } @@ -33,39 +33,39 @@ impl From for serde_json::Value { } impl Transformation { - pub fn auxdata(offset: usize, id: String) -> Self { + pub fn auxdata(offset: usize, id: impl Into) -> Self { Self { r#type: TransformationType::Replace, - reason: TransformationReason::Auxdata, + reason: TransformationReason::CborAuxdata, offset, - id: Some(id), + id: Some(id.into()), } } pub fn constructor(offset: usize) -> Self { Self { r#type: TransformationType::Insert, - reason: TransformationReason::Constructor, + reason: TransformationReason::ConstructorArguments, offset, id: None, } } - pub fn immutable(offset: usize, id: String) -> Self { + pub fn immutable(offset: usize, id: impl Into) -> Self { Self { r#type: TransformationType::Replace, reason: TransformationReason::Immutable, offset, - id: Some(id), + id: Some(id.into()), } } - pub fn library(offset: usize, id: String) -> Self { + pub fn library(offset: usize, id: impl Into) -> Self { Self { r#type: TransformationType::Replace, reason: TransformationReason::Library, offset, - id: Some(id), + id: Some(id.into()), } } } diff --git a/libs/verification-common/src/verifier_alliance/verification_match_values.rs b/libs/verification-common/src/verifier_alliance/verification_match_values.rs index 1ddab3df2..86f6cc255 100644 --- a/libs/verification-common/src/verifier_alliance/verification_match_values.rs +++ b/libs/verification-common/src/verifier_alliance/verification_match_values.rs @@ -6,19 +6,20 @@ use std::collections::BTreeMap; #[serde_as] #[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] +#[readonly::make] pub struct Values { - #[serde(skip_serializing_if = "BTreeMap::is_empty")] + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde_as(as = "BTreeMap<_, blockscout_display_bytes::serde_as::Hex>")] - cbor_auxdata: BTreeMap, - #[serde(skip_serializing_if = "Option::is_none")] + pub cbor_auxdata: BTreeMap, + #[serde(default, skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option")] - constructor_arguments: Option, - #[serde(skip_serializing_if = "BTreeMap::is_empty")] + pub constructor_arguments: Option, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde_as(as = "BTreeMap<_, blockscout_display_bytes::serde_as::Hex>")] - libraries: BTreeMap, - #[serde(skip_serializing_if = "BTreeMap::is_empty")] + pub libraries: BTreeMap, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde_as(as = "BTreeMap<_, blockscout_display_bytes::serde_as::Hex>")] - immutables: BTreeMap, + pub immutables: BTreeMap, } impl From for serde_json::Value {