From 52c41ecdf4dca82580893cd4dd026079f784d560 Mon Sep 17 00:00:00 2001 From: Rim Rakhimov Date: Mon, 17 Jul 2023 19:52:07 +0300 Subject: [PATCH] Verifier: allow partial values for the verification metadata (#565) * Update proto definition to have partially provided VerificationMetadata --- .../proto/v2/smart-contract-verifier.proto | 4 +- .../src/services/solidity_verifier.rs | 12 +++- .../src/services/vyper_verifier.rs | 12 +++- .../src/types/solidity_multi_part.rs | 6 +- .../src/types/solidity_standard_json.rs | 6 +- .../src/types/vyper_multi_part.rs | 6 +- .../src/types/vyper_standard_json.rs | 6 +- .../tests/vyper.rs | 62 +++++++++++++++++++ .../tests/vyper_types.rs | 26 +++++++- .../src/verifier/bytecode.rs | 2 +- 10 files changed, 122 insertions(+), 20 deletions(-) diff --git a/smart-contract-verifier/smart-contract-verifier-proto/proto/v2/smart-contract-verifier.proto b/smart-contract-verifier/smart-contract-verifier-proto/proto/v2/smart-contract-verifier.proto index 979312982..de08dcc71 100644 --- a/smart-contract-verifier/smart-contract-verifier-proto/proto/v2/smart-contract-verifier.proto +++ b/smart-contract-verifier/smart-contract-verifier-proto/proto/v2/smart-contract-verifier.proto @@ -75,9 +75,9 @@ enum BytecodeType { message VerificationMetadata { /// Id of the chain the contract is verified on - string chain_id = 1; + optional string chain_id = 1; /// The address of the contract to be verified - string contract_address = 2; + optional string contract_address = 2; } message VerifySolidityMultiPartRequest { diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/services/solidity_verifier.rs b/smart-contract-verifier/smart-contract-verifier-server/src/services/solidity_verifier.rs index d81bc3be6..4db250e28 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/services/solidity_verifier.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/services/solidity_verifier.rs @@ -85,7 +85,11 @@ impl SolidityVerifier for SolidityVerifierService { request: Request, ) -> Result, Status> { let request: VerifySolidityMultiPartRequestWrapper = request.into_inner().into(); - let chain_id = request.metadata.clone().unwrap_or_default().chain_id; + let chain_id = request + .metadata + .as_ref() + .and_then(|metadata| metadata.chain_id.clone()) + .unwrap_or_default(); let result = solidity::multi_part::verify(self.client.clone(), request.try_into()?).await; let response = if let Ok(verification_success) = result { @@ -121,7 +125,11 @@ impl SolidityVerifier for SolidityVerifierService { request: Request, ) -> Result, Status> { let request: VerifySolidityStandardJsonRequestWrapper = request.into_inner().into(); - let chain_id = request.metadata.clone().unwrap_or_default().chain_id; + let chain_id = request + .metadata + .as_ref() + .and_then(|metadata| metadata.chain_id.clone()) + .unwrap_or_default(); let verification_request = { let request: Result<_, StandardJsonParseError> = request.try_into(); if let Err(err) = request { diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/services/vyper_verifier.rs b/smart-contract-verifier/smart-contract-verifier-server/src/services/vyper_verifier.rs index 566fd6360..2ce13fe31 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/services/vyper_verifier.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/services/vyper_verifier.rs @@ -72,7 +72,11 @@ impl VyperVerifier for VyperVerifierService { request: Request, ) -> Result, Status> { let request: VerifyVyperMultiPartRequestWrapper = request.into_inner().into(); - let chain_id = request.metadata.clone().unwrap_or_default().chain_id; + let chain_id = request + .metadata + .as_ref() + .and_then(|metadata| metadata.chain_id.clone()) + .unwrap_or_default(); let result = vyper::multi_part::verify(self.client.clone(), request.try_into()?).await; let response = if let Ok(verification_success) = result { @@ -108,7 +112,11 @@ impl VyperVerifier for VyperVerifierService { request: Request, ) -> Result, Status> { let request: VerifyVyperStandardJsonRequestWrapper = request.into_inner().into(); - let chain_id = request.metadata.clone().unwrap_or_default().chain_id; + let chain_id = request + .metadata + .as_ref() + .and_then(|metadata| metadata.chain_id.clone()) + .unwrap_or_default(); let verification_request = { let request: Result<_, StandardJsonParseError> = request.try_into(); if let Err(err) = request { diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_multi_part.rs b/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_multi_part.rs index 98cf83add..626cde814 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_multi_part.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_multi_part.rs @@ -84,7 +84,7 @@ impl TryFrom for VerificationRequest { optimization_runs: request.optimization_runs.map(|i| i as usize), contract_libraries: Some(request.libraries.into_iter().collect()), }, - chain_id: request.metadata.map(|metadata| metadata.chain_id), + chain_id: request.metadata.and_then(|metadata| metadata.chain_id), }) } } @@ -108,8 +108,8 @@ mod tests { optimization_runs: Some(200), libraries: BTreeMap::from([("Lib".into(), "0xcafe".into())]), metadata: Some(VerificationMetadata { - chain_id: "1".into(), - contract_address: "0xcafecafecafecafecafecafecafecafecafecafe".into(), + chain_id: Some("1".into()), + contract_address: Some("0xcafecafecafecafecafecafecafecafecafecafe".into()), }), }; diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_standard_json.rs b/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_standard_json.rs index efc78c75c..08af3535f 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_standard_json.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/types/solidity_standard_json.rs @@ -63,7 +63,7 @@ impl TryFrom for VerificationRequest { creation_bytecode, compiler_version, content: StandardJsonContent { input }, - chain_id: request.metadata.map(|metadata| metadata.chain_id), + chain_id: request.metadata.and_then(|metadata| metadata.chain_id), }) } } @@ -84,8 +84,8 @@ mod tests { compiler_version: "v0.8.17+commit.8df45f5f".to_string(), input: "{\"language\": \"Solidity\", \"sources\": {\"./src/contracts/Foo.sol\": {\"content\": \"pragma solidity ^0.8.2;\\n\\ncontract Foo {\\n function bar() external pure returns (uint256) {\\n return 42;\\n }\\n}\\n\"}}, \"settings\": {\"metadata\": {\"useLiteralContent\": true}, \"optimizer\": {\"enabled\": true, \"runs\": 200}, \"outputSelection\": {\"*\": {\"*\": [\"abi\", \"evm.bytecode\", \"evm.deployedBytecode\", \"evm.methodIdentifiers\"], \"\": [\"id\", \"ast\"]}}}}".to_string(), metadata: Some(VerificationMetadata { - chain_id: "1".into(), - contract_address: "0xcafecafecafecafecafecafecafecafecafecafe".into() + chain_id: Some("1".into()), + contract_address: Some("0xcafecafecafecafecafecafecafecafecafecafe".into()) }), }; let input: CompilerInput = serde_json::from_str(&request.input).unwrap(); diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_multi_part.rs b/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_multi_part.rs index ff717ab1a..54ef40c40 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_multi_part.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_multi_part.rs @@ -88,7 +88,7 @@ impl TryFrom for VerificationRequest { interfaces, evm_version, }, - chain_id: request.metadata.map(|metadata| metadata.chain_id), + chain_id: request.metadata.and_then(|metadata| metadata.chain_id), }) } } @@ -109,8 +109,8 @@ mod tests { interfaces: BTreeMap::from([("interface_path".into(), "interface_content".into())]), evm_version: Some("byzantium".to_string()), metadata: Some(VerificationMetadata { - chain_id: "1".into(), - contract_address: "0xcafecafecafecafecafecafecafecafecafecafe".into(), + chain_id: Some("1".into()), + contract_address: Some("0xcafecafecafecafecafecafecafecafecafecafe".into()), }), }; diff --git a/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_standard_json.rs b/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_standard_json.rs index fd3c3e85c..0404b26fe 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_standard_json.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/src/types/vyper_standard_json.rs @@ -65,7 +65,7 @@ impl TryFrom for VerificationRequest { creation_bytecode, compiler_version, content: StandardJsonContent { input }, - chain_id: request.metadata.map(|metadata| metadata.chain_id), + chain_id: request.metadata.and_then(|metadata| metadata.chain_id), }) } } @@ -86,8 +86,8 @@ mod tests { compiler_version: "v0.3.7+commit.6020b8bb".to_string(), input: "{\"language\":\"Vyper\",\"sources\":{\"Contract.vy\":{\"content\":\"stored: address\\r\\n\\r\\nevent SingleVyper17: pass\\r\\n\\r\\n@internal\\r\\ndef extract(temp: address) -> address:\\r\\n ret: address = self.stored\\r\\n self.stored = temp\\r\\n return ret\\r\\n\\r\\n@external\\r\\ndef identity(x: address) -> address:\\r\\n log SingleVyper17()\\r\\n temp: address = self.stored\\r\\n self.stored = x\\r\\n return self.extract(temp)\"}},\"settings\":{\"outputSelection\":{\"*\":[\"evm\"]}}}".to_string(), metadata: Some(VerificationMetadata { - chain_id: "1".into(), - contract_address: "0xcafecafecafecafecafecafecafecafecafecafe".into() + chain_id: Some("1".into()), + contract_address: Some("0xcafecafecafecafecafecafecafecafecafecafe".into()), }), }; let input: CompilerInput = serde_json::from_str(&request.input).unwrap(); diff --git a/smart-contract-verifier/smart-contract-verifier-server/tests/vyper.rs b/smart-contract-verifier/smart-contract-verifier-server/tests/vyper.rs index ef25dcd2e..38ca731f4 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/tests/vyper.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/tests/vyper.rs @@ -253,6 +253,26 @@ mod flattened { test_case.creation_bytecode = "0xkeklol".to_string(); test_error(test_case, StatusCode::BAD_REQUEST, "Invalid bytecode: ").await; } + + #[tokio::test] + async fn accepts_partial_verification_metadata_in_input() { + // `chain_id` is provided, but `contract_address` is missed from the verification metadata + let test_case = { + let mut test_case = vyper_types::from_file::("simple"); + test_case.chain_id = Some("5".to_string()); + test_case + }; + test_success(test_case).await; + + // `contract_address` is provided, but `chain_id` is missed from the verification metadata + let test_case = { + let mut test_case = vyper_types::from_file::("simple"); + test_case.contract_address = + Some("0x0123456789012345678901234567890123456789".to_string()); + test_case + }; + test_success(test_case).await; + } } mod multi_part { @@ -266,6 +286,26 @@ mod multi_part { test_success(test_case).await; } } + + #[tokio::test] + async fn accepts_partial_verification_metadata_in_input() { + // `chain_id` is provided, but `contract_address` is missed from the verification metadata + let test_case = { + let mut test_case = vyper_types::from_file::("with_interfaces"); + test_case.chain_id = Some("5".to_string()); + test_case + }; + test_success(test_case).await; + + // `contract_address` is provided, but `chain_id` is missed from the verification metadata + let test_case = { + let mut test_case = vyper_types::from_file::("with_interfaces"); + test_case.contract_address = + Some("0x0123456789012345678901234567890123456789".to_string()); + test_case + }; + test_success(test_case).await; + } } mod standard_json { @@ -310,4 +350,26 @@ mod standard_json { ) .await; } + + #[tokio::test] + async fn accepts_partial_verification_metadata_in_input() { + // `chain_id` is provided, but `contract_address` is missed from the verification metadata + let test_case = { + let mut test_case = + vyper_types::from_file::("standard_json_with_interfaces"); + test_case.chain_id = Some("5".to_string()); + test_case + }; + test_success(test_case).await; + + // `contract_address` is provided, but `chain_id` is missed from the verification metadata + let test_case = { + let mut test_case = + vyper_types::from_file::("standard_json_with_interfaces"); + test_case.contract_address = + Some("0x0123456789012345678901234567890123456789".to_string()); + test_case + }; + test_success(test_case).await; + } } diff --git a/smart-contract-verifier/smart-contract-verifier-server/tests/vyper_types.rs b/smart-contract-verifier/smart-contract-verifier-server/tests/vyper_types.rs index e28b31102..a0b1e6163 100644 --- a/smart-contract-verifier/smart-contract-verifier-server/tests/vyper_types.rs +++ b/smart-contract-verifier/smart-contract-verifier-server/tests/vyper_types.rs @@ -47,6 +47,10 @@ pub struct Flattened { pub evm_version: Option, pub source_code: String, pub expected_constructor_argument: Option, + + // Verification metadata related values + pub chain_id: Option, + pub contract_address: Option, } fn default_flattened_contract_name() -> String { @@ -67,6 +71,10 @@ impl TestCase for Flattened { "sourceFiles": { format!("{}.vy", self.contract_name): self.source_code }, + "metadata": { + "chainId": self.chain_id, + "contractAddress": self.contract_address + } }) } @@ -106,6 +114,10 @@ pub struct MultiPart { pub source_files: BTreeMap, pub interfaces: BTreeMap, pub expected_constructor_argument: Option, + + // Verification metadata related values + pub chain_id: Option, + pub contract_address: Option, } impl TestCase for MultiPart { @@ -121,6 +133,10 @@ impl TestCase for MultiPart { "evmVersion": self.evm_version, "sourceFiles": self.source_files, "interfaces": self.interfaces, + "metadata": { + "chainId": self.chain_id, + "contractAddress": self.contract_address + } }) } @@ -169,6 +185,10 @@ pub struct StandardJson { #[serde(deserialize_with = "StandardJson::deserialize_input")] pub input: String, pub expected_constructor_argument: Option, + + // Verification metadata related values + pub chain_id: Option, + pub contract_address: Option, } impl StandardJson { @@ -191,7 +211,11 @@ impl TestCase for StandardJson { "bytecode": self.creation_bytecode, "bytecodeType": BytecodeType::CreationInput.as_str_name(), "compilerVersion": self.compiler_version, - "input": self.input + "input": self.input, + "metadata": { + "chainId": self.chain_id, + "contractAddress": self.contract_address + } }) } diff --git a/smart-contract-verifier/smart-contract-verifier/src/verifier/bytecode.rs b/smart-contract-verifier/smart-contract-verifier/src/verifier/bytecode.rs index 94d0da4d5..00bffc378 100644 --- a/smart-contract-verifier/smart-contract-verifier/src/verifier/bytecode.rs +++ b/smart-contract-verifier/smart-contract-verifier/src/verifier/bytecode.rs @@ -106,7 +106,7 @@ impl Bytecode { Ok(Self { bytecode, - source: PhantomData::default(), + source: PhantomData, }) }