write `CompactContractBytecode` instead of `CompactContract` (#833)
* write `CompactContractBytecode` instead of `CompactContract` * chore: fix doctest Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
parent
ec2b51539d
commit
24c39bd32a
|
@ -814,6 +814,21 @@ impl ContractBytecode {
|
|||
deployed_bytecode: self.deployed_bytecode.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks for all link references in deployment and runtime bytecodes
|
||||
pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
|
||||
let mut links = BTreeMap::new();
|
||||
if let Some(bcode) = &self.bytecode {
|
||||
links.extend(bcode.link_references.clone());
|
||||
}
|
||||
|
||||
if let Some(d_bcode) = &self.deployed_bytecode {
|
||||
if let Some(bcode) = &d_bcode.bytecode {
|
||||
links.extend(bcode.link_references.clone());
|
||||
}
|
||||
}
|
||||
links
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Contract> for ContractBytecode {
|
||||
|
@ -828,6 +843,80 @@ impl From<Contract> for ContractBytecode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Minimal representation of a contract with a present abi and bytecode.
|
||||
///
|
||||
/// Unlike `CompactContractSome` which contains the `BytecodeObject`, this holds the whole
|
||||
/// `Bytecode` object.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct CompactContractBytecode {
|
||||
/// The Ethereum Contract ABI. If empty, it is represented as an empty
|
||||
/// array. See https://docs.soliditylang.org/en/develop/abi-spec.html
|
||||
pub abi: Option<Abi>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bytecode: Option<CompactBytecode>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub deployed_bytecode: Option<CompactDeployedBytecode>,
|
||||
}
|
||||
|
||||
impl CompactContractBytecode {
|
||||
/// Looks for all link references in deployment and runtime bytecodes
|
||||
pub fn all_link_references(&self) -> BTreeMap<String, BTreeMap<String, Vec<Offsets>>> {
|
||||
let mut links = BTreeMap::new();
|
||||
if let Some(bcode) = &self.bytecode {
|
||||
links.extend(bcode.link_references.clone());
|
||||
}
|
||||
|
||||
if let Some(d_bcode) = &self.deployed_bytecode {
|
||||
if let Some(bcode) = &d_bcode.bytecode {
|
||||
links.extend(bcode.link_references.clone());
|
||||
}
|
||||
}
|
||||
links
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Contract> for CompactContractBytecode {
|
||||
fn from(c: Contract) -> Self {
|
||||
let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
|
||||
let (maybe_bcode, maybe_runtime) = match (evm.bytecode, evm.deployed_bytecode) {
|
||||
(Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
|
||||
(None, Some(dbcode)) => (None, Some(dbcode.into())),
|
||||
(Some(bcode), None) => (Some(bcode.into()), None),
|
||||
(None, None) => (None, None),
|
||||
};
|
||||
(maybe_bcode, maybe_runtime)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
Self { abi: c.abi, bytecode, deployed_bytecode }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ContractBytecode> for CompactContractBytecode {
|
||||
fn from(c: ContractBytecode) -> Self {
|
||||
let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
|
||||
(Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
|
||||
(None, Some(dbcode)) => (None, Some(dbcode.into())),
|
||||
(Some(bcode), None) => (Some(bcode.into()), None),
|
||||
(None, None) => (None, None),
|
||||
};
|
||||
Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompactContractBytecode> for ContractBytecode {
|
||||
fn from(c: CompactContractBytecode) -> Self {
|
||||
let (maybe_bcode, maybe_runtime) = match (c.bytecode, c.deployed_bytecode) {
|
||||
(Some(bcode), Some(dbcode)) => (Some(bcode.into()), Some(dbcode.into())),
|
||||
(None, Some(dbcode)) => (None, Some(dbcode.into())),
|
||||
(Some(bcode), None) => (Some(bcode.into()), None),
|
||||
(None, None) => (None, None),
|
||||
};
|
||||
Self { abi: c.abi, bytecode: maybe_bcode, deployed_bytecode: maybe_runtime }
|
||||
}
|
||||
}
|
||||
|
||||
/// Minimal representation of a contract with a present abi and bytecode.
|
||||
///
|
||||
/// Unlike `CompactContractSome` which contains the `BytecodeObject`, this holds the whole
|
||||
|
@ -971,6 +1060,13 @@ impl From<ContractBytecode> for CompactContract {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CompactContractBytecode> for CompactContract {
|
||||
fn from(c: CompactContractBytecode) -> Self {
|
||||
let c: ContractBytecode = c.into();
|
||||
c.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ContractBytecodeSome> for CompactContract {
|
||||
fn from(c: ContractBytecodeSome) -> Self {
|
||||
Self {
|
||||
|
@ -1183,6 +1279,88 @@ pub struct Bytecode {
|
|||
pub link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompactBytecode {
|
||||
/// The bytecode as a hex string.
|
||||
pub object: BytecodeObject,
|
||||
/// The source mapping as a string. See the source mapping definition.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_map: Option<String>,
|
||||
/// If given, this is an unlinked object.
|
||||
#[serde(default)]
|
||||
pub link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
|
||||
}
|
||||
|
||||
impl CompactBytecode {
|
||||
/// Tries to link the bytecode object with the `file` and `library` name.
|
||||
/// Replaces all library placeholders with the given address.
|
||||
///
|
||||
/// Returns true if the bytecode object is fully linked, false otherwise
|
||||
/// This is a noop if the bytecode object is already fully linked.
|
||||
pub fn link(
|
||||
&mut self,
|
||||
file: impl AsRef<str>,
|
||||
library: impl AsRef<str>,
|
||||
address: Address,
|
||||
) -> bool {
|
||||
if !self.object.is_unlinked() {
|
||||
return true
|
||||
}
|
||||
|
||||
let file = file.as_ref();
|
||||
let library = library.as_ref();
|
||||
if let Some((key, mut contracts)) = self.link_references.remove_entry(file) {
|
||||
if contracts.remove(library).is_some() {
|
||||
self.object.link(file, library, address);
|
||||
}
|
||||
if !contracts.is_empty() {
|
||||
self.link_references.insert(key, contracts);
|
||||
}
|
||||
if self.link_references.is_empty() {
|
||||
return self.object.resolve().is_some()
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Bytecode> for CompactBytecode {
|
||||
fn from(bcode: Bytecode) -> CompactBytecode {
|
||||
CompactBytecode {
|
||||
object: bcode.object,
|
||||
source_map: bcode.source_map,
|
||||
link_references: bcode.link_references,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompactBytecode> for Bytecode {
|
||||
fn from(bcode: CompactBytecode) -> Bytecode {
|
||||
Bytecode {
|
||||
object: bcode.object,
|
||||
source_map: bcode.source_map,
|
||||
link_references: bcode.link_references,
|
||||
function_debug_data: Default::default(),
|
||||
opcodes: Default::default(),
|
||||
generated_sources: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BytecodeObject> for Bytecode {
|
||||
fn from(object: BytecodeObject) -> Bytecode {
|
||||
Bytecode {
|
||||
object,
|
||||
function_debug_data: Default::default(),
|
||||
opcodes: Default::default(),
|
||||
source_map: Default::default(),
|
||||
generated_sources: Default::default(),
|
||||
link_references: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytecode {
|
||||
/// Returns the parsed source map
|
||||
///
|
||||
|
@ -1453,6 +1631,43 @@ impl DeployedBytecode {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Bytecode> for DeployedBytecode {
|
||||
fn from(bcode: Bytecode) -> DeployedBytecode {
|
||||
DeployedBytecode { bytecode: Some(bcode), immutable_references: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CompactDeployedBytecode {
|
||||
#[serde(flatten)]
|
||||
pub bytecode: Option<CompactBytecode>,
|
||||
#[serde(
|
||||
default,
|
||||
rename = "immutableReferences",
|
||||
skip_serializing_if = "::std::collections::BTreeMap::is_empty"
|
||||
)]
|
||||
pub immutable_references: BTreeMap<String, Vec<Offsets>>,
|
||||
}
|
||||
|
||||
impl From<DeployedBytecode> for CompactDeployedBytecode {
|
||||
fn from(bcode: DeployedBytecode) -> CompactDeployedBytecode {
|
||||
CompactDeployedBytecode {
|
||||
bytecode: bcode.bytecode.map(|d_bcode| d_bcode.into()),
|
||||
immutable_references: bcode.immutable_references,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompactDeployedBytecode> for DeployedBytecode {
|
||||
fn from(bcode: CompactDeployedBytecode) -> DeployedBytecode {
|
||||
DeployedBytecode {
|
||||
bytecode: bcode.bytecode.map(|d_bcode| d_bcode.into()),
|
||||
immutable_references: bcode.immutable_references,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct GasEstimates {
|
||||
pub creation: Creation,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
artifacts::{CompactContract, CompactContractRef, Contract, Settings},
|
||||
artifacts::{CompactContract, CompactContractBytecode, Contract, Settings},
|
||||
cache::SOLIDITY_FILES_CACHE_FILENAME,
|
||||
error::{Result, SolcError, SolcIoError},
|
||||
hh::HardhatArtifact,
|
||||
|
@ -503,14 +503,20 @@ pub trait Artifact {
|
|||
/// Returns the artifact's `Abi` and bytecode
|
||||
fn into_inner(self) -> (Option<Abi>, Option<Bytes>);
|
||||
|
||||
/// Turns the artifact into a container type for abi, bytecode and deployed bytecode
|
||||
/// Turns the artifact into a container type for abi, compact bytecode and deployed bytecode
|
||||
fn into_compact_contract(self) -> CompactContract;
|
||||
|
||||
/// Turns the artifact into a container type for abi, full bytecode and deployed bytecode
|
||||
fn into_contract_bytecode(self) -> CompactContractBytecode;
|
||||
|
||||
/// Returns the contents of this type as a single tuple of abi, bytecode and deployed bytecode
|
||||
fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>);
|
||||
}
|
||||
|
||||
impl<T: Into<CompactContract>> Artifact for T {
|
||||
impl<T> Artifact for T
|
||||
where
|
||||
T: Into<CompactContractBytecode> + Into<CompactContract>,
|
||||
{
|
||||
fn into_inner(self) -> (Option<Abi>, Option<Bytes>) {
|
||||
let artifact = self.into_compact_contract();
|
||||
(artifact.abi, artifact.bin.and_then(|bin| bin.into_bytes()))
|
||||
|
@ -520,6 +526,10 @@ impl<T: Into<CompactContract>> Artifact for T {
|
|||
self.into()
|
||||
}
|
||||
|
||||
fn into_contract_bytecode(self) -> CompactContractBytecode {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
|
||||
self.into_compact_contract().into_parts()
|
||||
}
|
||||
|
@ -625,7 +635,7 @@ pub trait ArtifactOutput {
|
|||
pub struct MinimalCombinedArtifacts;
|
||||
|
||||
impl ArtifactOutput for MinimalCombinedArtifacts {
|
||||
type Artifact = CompactContract;
|
||||
type Artifact = CompactContractBytecode;
|
||||
|
||||
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
||||
fs::create_dir_all(&layout.artifacts)
|
||||
|
@ -643,7 +653,7 @@ impl ArtifactOutput for MinimalCombinedArtifacts {
|
|||
))
|
||||
})?;
|
||||
}
|
||||
let min = CompactContractRef::from(contract);
|
||||
let min = CompactContractBytecode::from(contract.clone());
|
||||
fs::write(&file, serde_json::to_vec_pretty(&min)?)
|
||||
.map_err(|err| SolcError::io(err, file))?
|
||||
}
|
||||
|
@ -662,7 +672,7 @@ impl ArtifactOutput for MinimalCombinedArtifacts {
|
|||
pub struct MinimalCombinedArtifactsHardhatFallback;
|
||||
|
||||
impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
|
||||
type Artifact = CompactContract;
|
||||
type Artifact = CompactContractBytecode;
|
||||
|
||||
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
||||
MinimalCombinedArtifacts::on_output(output, layout)
|
||||
|
@ -678,7 +688,7 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
|
|||
tracing::trace!("Fallback to hardhat artifact deserialization");
|
||||
let artifact = serde_json::from_str::<HardhatArtifact>(&content)?;
|
||||
tracing::trace!("successfully deserialized hardhat artifact");
|
||||
Ok(artifact.into_compact_contract())
|
||||
Ok(artifact.into_contract_bytecode())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
//! Hardhat support
|
||||
|
||||
use crate::{
|
||||
artifacts::{BytecodeObject, CompactContract, Contract, Offsets},
|
||||
artifacts::{
|
||||
Bytecode, BytecodeObject, CompactContract, CompactContractBytecode, Contract,
|
||||
ContractBytecode, DeployedBytecode, Offsets,
|
||||
},
|
||||
error::{Result, SolcError},
|
||||
ArtifactOutput, CompilerOutput, ProjectPathsConfig,
|
||||
};
|
||||
|
@ -49,6 +52,32 @@ impl From<HardhatArtifact> for CompactContract {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<HardhatArtifact> for ContractBytecode {
|
||||
fn from(artifact: HardhatArtifact) -> Self {
|
||||
let bytecode: Option<Bytecode> = artifact.bytecode.as_ref().map(|t| {
|
||||
let mut bcode: Bytecode = t.clone().into();
|
||||
bcode.link_references = artifact.link_references.clone();
|
||||
bcode
|
||||
});
|
||||
|
||||
let deployed_bytecode: Option<DeployedBytecode> = artifact.bytecode.as_ref().map(|t| {
|
||||
let mut bcode: Bytecode = t.clone().into();
|
||||
bcode.link_references = artifact.deployed_link_references.clone();
|
||||
bcode.into()
|
||||
});
|
||||
|
||||
ContractBytecode { abi: Some(artifact.abi), bytecode, deployed_bytecode }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HardhatArtifact> for CompactContractBytecode {
|
||||
fn from(artifact: HardhatArtifact) -> Self {
|
||||
let c: ContractBytecode = artifact.into();
|
||||
|
||||
c.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Hardhat style artifacts handler
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct HardhatArtifacts;
|
||||
|
|
|
@ -918,11 +918,11 @@ impl<T: ArtifactOutput + 'static> ProjectCompileOutput<T> {
|
|||
///
|
||||
/// ```no_run
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use ethers_solc::artifacts::CompactContract;
|
||||
/// use ethers_solc::artifacts::CompactContractBytecode;
|
||||
/// use ethers_solc::Project;
|
||||
///
|
||||
/// let project = Project::builder().build().unwrap();
|
||||
/// let contracts: BTreeMap<String, CompactContract> = project.compile().unwrap().into_artifacts().collect();
|
||||
/// let contracts: BTreeMap<String, CompactContractBytecode> = project.compile().unwrap().into_artifacts().collect();
|
||||
/// ```
|
||||
pub fn into_artifacts(mut self) -> Box<dyn Iterator<Item = (String, T::Artifact)>> {
|
||||
let artifacts = self.artifacts.into_iter().filter_map(|(path, art)| {
|
||||
|
|
Loading…
Reference in New Issue