Skip to content

Commit

Permalink
eth-bytecode-db: update server to support verifier alliance database (#…
Browse files Browse the repository at this point in the history
…620)

* Add integration tests for the verifier alliance test cases

* Actual implementation of verifier alliance database insertion

* Extened verification metadata struct in the API. Add test cases for authorized requests

* Add deployement data storage in case of authorized request

* Copy verifier alliance tests into server implementation. Update api verification endpoints and implementations to support verifier alliance setup

* Add missing dependencies
  • Loading branch information
rimrakhimov authored Oct 14, 2023
1 parent 5513415 commit f4aa8eb
Show file tree
Hide file tree
Showing 33 changed files with 2,087 additions and 175 deletions.
40 changes: 9 additions & 31 deletions eth-bytecode-db/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ message VerificationMetadata {
optional string chain_id = 1;
/// The address of the contract to be verified
optional string contract_address = 2;
/// The hash of the transaction the contract has been created at
optional string transaction_hash = 3;
/// The number of the block containing the creation transaction
optional int64 block_number = 4;
/// The position number transaction has been added into a block
optional int64 transaction_index = 5;
/// The address which actually deployed the contract (i.e. called the create/create2 opcode)
optional string deployer = 6;
/// The bytecode from the calldata (for eoa deployments) or given to create/create2
optional string creation_code = 7;
// The bytecode actually stored in the blockchain for the given contract
optional string runtime_code = 8;
}

message VerifySolidityMultiPartRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,32 @@ definitions:
v2VerificationMetadata:
type: object
properties:
blockNumber:
type: string
format: int64
title: / The number of the block containing the creation transaction
chainId:
type: string
title: / Id of the chain the contract is verified on
contractAddress:
type: string
title: / The address of the contract to be verified
creationCode:
type: string
title: / The bytecode from the calldata (for eoa deployments) or given to create/create2
deployer:
type: string
title: / The address which actually deployed the contract (i.e. called the create/create2 opcode)
runtimeCode:
type: string
title: The bytecode actually stored in the blockchain for the given contract
transactionHash:
type: string
title: / The hash of the transaction the contract has been created at
transactionIndex:
type: string
format: int64
title: / The position number transaction has been added into a block
v2VerifyFromEtherscanSourcifyRequest:
type: object
properties:
Expand Down
6 changes: 5 additions & 1 deletion eth-bytecode-db/eth-bytecode-db-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ tracing = "0.1"

[dev-dependencies]
smart-contract-verifier-proto = { git = "https://github.com/blockscout/blockscout-rs", rev = "2480b20" }
verifier-alliance-entity = { path = "../eth-bytecode-db/verifier-alliance-entity" }
verifier-alliance-migration = { path = "../eth-bytecode-db/verifier-alliance-migration" }

bytes = "1.5.0"
hex = "0.4.3"
mockall = "0.11"
keccak-hash = "0.10.0"
pretty_assertions = "1.3"
reqwest = { version = "0.11", features = ["json"]}
rand = "0.8"
rstest = "0.16"
rstest = "0.18.2"
sea-orm = { version = "*", features = [ "sqlx-sqlite" ]}
tokio-stream = { version = "0.1", features = ["net"] }
22 changes: 18 additions & 4 deletions eth-bytecode-db/eth-bytecode-db-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
use blockscout_service_launcher::{database, launcher, launcher::LaunchSettings, tracing};
use eth_bytecode_db::verification::Client;
use migration::Migrator;
use std::sync::Arc;
use std::{collections::HashSet, sync::Arc};

const SERVICE_NAME: &str = "eth_bytecode_db";

Expand Down Expand Up @@ -84,7 +84,12 @@ pub async fn run(settings: Settings) -> Result<(), anyhow::Error> {
.await?;

let db_connection = Arc::new(sea_orm::Database::connect(settings.database.url).await?);
let client = Client::new_arc(db_connection.clone(), settings.verifier.uri).await?;
let mut client = Client::new_arc(db_connection.clone(), settings.verifier.uri).await?;
if settings.verifier_alliance_database.enabled {
let alliance_db_connection =
sea_orm::Database::connect(settings.verifier_alliance_database.url).await?;
client = client.with_alliance_db(alliance_db_connection);
}

let sourcify_client = sourcify::ClientBuilder::default()
.try_base_url(&settings.sourcify.base_url)
Expand All @@ -93,8 +98,17 @@ pub async fn run(settings: Settings) -> Result<(), anyhow::Error> {
.build();
let database = Arc::new(DatabaseService::new_arc(client.clone(), sourcify_client));

let solidity_verifier = Arc::new(SolidityVerifierService::new(client.clone()));
let vyper_verifier = Arc::new(VyperVerifierService::new(client.clone()));
let authorized_keys: HashSet<_> = settings
.authorized_keys
.into_values()
.map(|key| key.key)
.collect();

let solidity_verifier = Arc::new(
SolidityVerifierService::new(client.clone()).with_authorized_keys(authorized_keys.clone()),
);
let vyper_verifier =
Arc::new(VyperVerifierService::new(client.clone()).with_authorized_keys(authorized_keys));
let sourcify_verifier = Arc::new(SourcifyVerifierService::new(client.clone()));

let router = Router {
Expand Down
24 changes: 24 additions & 0 deletions eth-bytecode-db/eth-bytecode-db-server/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,27 @@ pub use health::HealthService;
pub use solidity_verifier::SolidityVerifierService;
pub use sourcify_verifier::SourcifyVerifierService;
pub use vyper_verifier::VyperVerifierService;

/****************************************************************************/

const API_KEY_NAME: &str = "x-api-key";

fn is_key_authorized(
authorized_keys: &std::collections::HashSet<String>,
metadata: tonic::metadata::MetadataMap,
) -> Result<bool, tonic::Status> {
let api_key = metadata
.get(API_KEY_NAME)
.map(|api_key| api_key.to_str())
.transpose()
.map_err(|err| {
tonic::Status::invalid_argument(format!(
"invalid api key value ({API_KEY_NAME}): {err}"
))
})?;

let is_authorized = api_key
.map(|key| authorized_keys.contains(key))
.unwrap_or_default();
Ok(is_authorized)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,24 @@ use async_trait::async_trait;
use eth_bytecode_db::verification::{
compiler_versions, solidity_multi_part, solidity_standard_json, Client, VerificationRequest,
};
use std::collections::HashSet;

pub struct SolidityVerifierService {
client: Client,
authorized_keys: HashSet<String>,
}

impl SolidityVerifierService {
pub fn new(client: Client) -> Self {
Self { client }
Self {
client,
authorized_keys: Default::default(),
}
}

pub fn with_authorized_keys(mut self, authorized_keys: HashSet<String>) -> Self {
self.authorized_keys = authorized_keys;
self
}
}

Expand All @@ -28,7 +38,7 @@ impl solidity_verifier_server::SolidityVerifier for SolidityVerifierService {
&self,
request: tonic::Request<VerifySolidityMultiPartRequest>,
) -> Result<tonic::Response<VerifyResponse>, tonic::Status> {
let request = request.into_inner();
let (metadata, _, request) = request.into_parts();

let bytecode_type = request.bytecode_type();
let verification_request = VerificationRequest {
Expand All @@ -45,6 +55,7 @@ impl solidity_verifier_server::SolidityVerifier for SolidityVerifierService {
.metadata
.map(|metadata| VerificationMetadataWrapper::from_inner(metadata).try_into())
.transpose()?,
is_authorized: super::is_key_authorized(&self.authorized_keys, metadata)?,
};
let result = solidity_multi_part::verify(self.client.clone(), verification_request).await;

Expand All @@ -55,7 +66,7 @@ impl solidity_verifier_server::SolidityVerifier for SolidityVerifierService {
&self,
request: tonic::Request<VerifySolidityStandardJsonRequest>,
) -> Result<tonic::Response<VerifyResponse>, tonic::Status> {
let request = request.into_inner();
let (metadata, _, request) = request.into_parts();

let bytecode_type = request.bytecode_type();
let verification_request = VerificationRequest {
Expand All @@ -69,6 +80,7 @@ impl solidity_verifier_server::SolidityVerifier for SolidityVerifierService {
.metadata
.map(|metadata| VerificationMetadataWrapper::from_inner(metadata).try_into())
.transpose()?,
is_authorized: super::is_key_authorized(&self.authorized_keys, metadata)?,
};
let result =
solidity_standard_json::verify(self.client.clone(), verification_request).await;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,24 @@ use async_trait::async_trait;
use eth_bytecode_db::verification::{
compiler_versions, vyper_multi_part, vyper_standard_json, Client, VerificationRequest,
};
use std::collections::HashSet;

pub struct VyperVerifierService {
client: Client,
authorized_keys: HashSet<String>,
}

impl VyperVerifierService {
pub fn new(client: Client) -> Self {
Self { client }
Self {
client,
authorized_keys: Default::default(),
}
}

pub fn with_authorized_keys(mut self, authorized_keys: HashSet<String>) -> Self {
self.authorized_keys = authorized_keys;
self
}
}

Expand All @@ -28,7 +38,7 @@ impl vyper_verifier_server::VyperVerifier for VyperVerifierService {
&self,
request: tonic::Request<VerifyVyperMultiPartRequest>,
) -> Result<tonic::Response<VerifyResponse>, tonic::Status> {
let request = request.into_inner();
let (metadata, _, request) = request.into_parts();

let bytecode_type = request.bytecode_type();
let verification_request = VerificationRequest {
Expand All @@ -44,6 +54,7 @@ impl vyper_verifier_server::VyperVerifier for VyperVerifierService {
.metadata
.map(|metadata| VerificationMetadataWrapper::from_inner(metadata).try_into())
.transpose()?,
is_authorized: super::is_key_authorized(&self.authorized_keys, metadata)?,
};
let result = vyper_multi_part::verify(self.client.clone(), verification_request).await;

Expand All @@ -54,7 +65,7 @@ impl vyper_verifier_server::VyperVerifier for VyperVerifierService {
&self,
request: tonic::Request<VerifyVyperStandardJsonRequest>,
) -> Result<tonic::Response<VerifyResponse>, tonic::Status> {
let request = request.into_inner();
let (metadata, _, request) = request.into_parts();

let bytecode_type = request.bytecode_type();
let verification_request = VerificationRequest {
Expand All @@ -68,6 +79,7 @@ impl vyper_verifier_server::VyperVerifier for VyperVerifierService {
.metadata
.map(|metadata| VerificationMetadataWrapper::from_inner(metadata).try_into())
.transpose()?,
is_authorized: super::is_key_authorized(&self.authorized_keys, metadata)?,
};
let result = vyper_standard_json::verify(self.client.clone(), verification_request).await;

Expand Down
Loading

0 comments on commit f4aa8eb

Please sign in to comment.