From 9892756ee4044e1ccfb6b253c972210c85d9b28e Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 30 Jun 2022 18:16:47 +0200 Subject: [PATCH] feat(solc): include opcodes in output (#1435) --- .../src/artifact_output/configurable.rs | 24 ++++++++++++++++++- ethers-solc/src/artifact_output/mod.rs | 23 ++++++++---------- ethers-solc/tests/project.rs | 2 ++ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/ethers-solc/src/artifact_output/configurable.rs b/ethers-solc/src/artifact_output/configurable.rs index a964b20e..7958a211 100644 --- a/ethers-solc/src/artifact_output/configurable.rs +++ b/ethers-solc/src/artifact_output/configurable.rs @@ -1,4 +1,12 @@ //! A configurable artifacts handler implementation +//! +//! Configuring artifacts requires two pieces: the `ConfigurableArtifacts` handler, which contains +//! the configuration of how to construct the `ConfigurableArtifact` type based on a `Contract`. The +//! `ConfigurableArtifacts` populates a single `Artifact`, the `ConfigurableArtifact`, by default +//! with essential entries only, such as `abi`, `bytecode`,..., but may include additional values +//! based on its `ExtraOutputValues` that maps to various objects in the solc contract output, see +//! also: [`OutputSelection`](crate::artifacts::OutputSelection). In addition to that some output +//! values can also be emitted as standalone files. use crate::{ artifacts::{ @@ -34,6 +42,8 @@ pub struct ConfigurableContractArtifact { #[serde(default, skip_serializing_if = "Option::is_none")] pub assembly: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub opcodes: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub method_identifiers: Option>, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub generated_sources: Vec, @@ -248,6 +258,7 @@ impl ArtifactOutput for ConfigurableArtifacts { let mut artifact_assembly = None; let mut artifact_storage_layout = None; let mut generated_sources = None; + let mut opcodes = None; let Contract { abi, @@ -298,13 +309,17 @@ impl ArtifactOutput for ConfigurableArtifacts { if self.additional_values.function_debug_data { artifact_function_debug_data = - bytecode.as_ref().map(|b| b.function_debug_data.clone()); + bytecode.as_mut().map(|code| std::mem::take(&mut code.function_debug_data)); } if self.additional_values.generated_sources { generated_sources = bytecode.as_mut().map(|code| std::mem::take(&mut code.generated_sources)); } + if self.additional_values.opcodes { + opcodes = bytecode.as_mut().and_then(|code| code.opcodes.take()) + } + artifact_bytecode = bytecode.map(Into::into); artifact_deployed_bytecode = deployed_bytecode.map(Into::into); artifact_method_identifiers = Some(method_identifiers); @@ -322,6 +337,7 @@ impl ArtifactOutput for ConfigurableArtifacts { bytecode: artifact_bytecode, deployed_bytecode: artifact_deployed_bytecode, assembly: artifact_assembly, + opcodes, function_debug_data: artifact_function_debug_data, method_identifiers: artifact_method_identifiers, gas_estimates: artifact_gas_estimates, @@ -373,6 +389,7 @@ pub struct ExtraOutputValues { pub function_debug_data: bool, pub generated_sources: bool, pub source_map: bool, + pub opcodes: bool, /// PRIVATE: This structure may grow, As such, constructing this structure should /// _always_ be done using a public constructor or update syntax: @@ -408,6 +425,7 @@ impl ExtraOutputValues { function_debug_data: true, generated_sources: true, source_map: true, + opcodes: true, __non_exhaustive: (), } } @@ -444,6 +462,7 @@ impl ExtraOutputValues { config.method_identifiers = true; config.generated_sources = true; config.source_map = true; + config.opcodes = true; } EvmOutputSelection::Assembly => { config.assembly = true; @@ -457,6 +476,9 @@ impl ExtraOutputValues { EvmOutputSelection::ByteCode(BytecodeOutputSelection::FunctionDebugData) => { config.function_debug_data = true; } + EvmOutputSelection::ByteCode(BytecodeOutputSelection::Opcodes) => { + config.opcodes = true; + } EvmOutputSelection::ByteCode(BytecodeOutputSelection::GeneratedSources) => { config.generated_sources = true; } diff --git a/ethers-solc/src/artifact_output/mod.rs b/ethers-solc/src/artifact_output/mod.rs index db5be8f9..616e6cdb 100644 --- a/ethers-solc/src/artifact_output/mod.rs +++ b/ethers-solc/src/artifact_output/mod.rs @@ -1,8 +1,16 @@ //! Output artifact handling use crate::{ - artifacts::FileToContractsMap, error::Result, utils, HardhatArtifact, ProjectPathsConfig, - SolcError, + artifacts::{ + contract::{CompactContract, CompactContractBytecode, Contract}, + BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode, + FileToContractsMap, SourceFile, + }, + compile::output::{contracts::VersionedContracts, sources::VersionedSourceFiles}, + error::Result, + sourcemap::{SourceMap, SyntaxError}, + sources::VersionedSourceFile, + utils, HardhatArtifact, ProjectPathsConfig, SolcError, }; use ethers_core::{abi::Abi, types::Bytes}; use semver::Version; @@ -13,18 +21,7 @@ use std::{ fmt, fs, io, path::{Path, PathBuf}, }; - mod configurable; -use crate::{ - artifacts::{ - contract::{CompactContract, CompactContractBytecode, Contract}, - BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode, - SourceFile, - }, - compile::output::{contracts::VersionedContracts, sources::VersionedSourceFiles}, - sourcemap::{SourceMap, SyntaxError}, - sources::VersionedSourceFile, -}; pub use configurable::*; /// Represents unique artifact metadata for identifying artifacts on output diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index f02ef995..322e7a20 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -139,6 +139,7 @@ fn can_compile_configured() { metadata: true, ir: true, ir_optimized: true, + opcodes: true, ..Default::default() }, ..Default::default() @@ -152,6 +153,7 @@ fn can_compile_configured() { assert!(artifact.raw_metadata.is_some()); assert!(artifact.ir.is_some()); assert!(artifact.ir_optimized.is_some()); + assert!(artifact.opcodes.is_some()); } #[test]