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(),
|
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 {
|
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.
|
/// Minimal representation of a contract with a present abi and bytecode.
|
||||||
///
|
///
|
||||||
/// Unlike `CompactContractSome` which contains the `BytecodeObject`, this holds the whole
|
/// 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 {
|
impl From<ContractBytecodeSome> for CompactContract {
|
||||||
fn from(c: ContractBytecodeSome) -> Self {
|
fn from(c: ContractBytecodeSome) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -1183,6 +1279,88 @@ pub struct Bytecode {
|
||||||
pub link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
|
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 {
|
impl Bytecode {
|
||||||
/// Returns the parsed source map
|
/// 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)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct GasEstimates {
|
pub struct GasEstimates {
|
||||||
pub creation: Creation,
|
pub creation: Creation,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
artifacts::{CompactContract, CompactContractRef, Contract, Settings},
|
artifacts::{CompactContract, CompactContractBytecode, Contract, Settings},
|
||||||
cache::SOLIDITY_FILES_CACHE_FILENAME,
|
cache::SOLIDITY_FILES_CACHE_FILENAME,
|
||||||
error::{Result, SolcError, SolcIoError},
|
error::{Result, SolcError, SolcIoError},
|
||||||
hh::HardhatArtifact,
|
hh::HardhatArtifact,
|
||||||
|
@ -503,14 +503,20 @@ pub trait Artifact {
|
||||||
/// Returns the artifact's `Abi` and bytecode
|
/// Returns the artifact's `Abi` and bytecode
|
||||||
fn into_inner(self) -> (Option<Abi>, Option<Bytes>);
|
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;
|
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
|
/// 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>);
|
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>) {
|
fn into_inner(self) -> (Option<Abi>, Option<Bytes>) {
|
||||||
let artifact = self.into_compact_contract();
|
let artifact = self.into_compact_contract();
|
||||||
(artifact.abi, artifact.bin.and_then(|bin| bin.into_bytes()))
|
(artifact.abi, artifact.bin.and_then(|bin| bin.into_bytes()))
|
||||||
|
@ -520,6 +526,10 @@ impl<T: Into<CompactContract>> Artifact for T {
|
||||||
self.into()
|
self.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_contract_bytecode(self) -> CompactContractBytecode {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
|
||||||
fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
|
fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
|
||||||
self.into_compact_contract().into_parts()
|
self.into_compact_contract().into_parts()
|
||||||
}
|
}
|
||||||
|
@ -625,7 +635,7 @@ pub trait ArtifactOutput {
|
||||||
pub struct MinimalCombinedArtifacts;
|
pub struct MinimalCombinedArtifacts;
|
||||||
|
|
||||||
impl ArtifactOutput for MinimalCombinedArtifacts {
|
impl ArtifactOutput for MinimalCombinedArtifacts {
|
||||||
type Artifact = CompactContract;
|
type Artifact = CompactContractBytecode;
|
||||||
|
|
||||||
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
||||||
fs::create_dir_all(&layout.artifacts)
|
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)?)
|
fs::write(&file, serde_json::to_vec_pretty(&min)?)
|
||||||
.map_err(|err| SolcError::io(err, file))?
|
.map_err(|err| SolcError::io(err, file))?
|
||||||
}
|
}
|
||||||
|
@ -662,7 +672,7 @@ impl ArtifactOutput for MinimalCombinedArtifacts {
|
||||||
pub struct MinimalCombinedArtifactsHardhatFallback;
|
pub struct MinimalCombinedArtifactsHardhatFallback;
|
||||||
|
|
||||||
impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
|
impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
|
||||||
type Artifact = CompactContract;
|
type Artifact = CompactContractBytecode;
|
||||||
|
|
||||||
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
fn on_output(output: &CompilerOutput, layout: &ProjectPathsConfig) -> Result<()> {
|
||||||
MinimalCombinedArtifacts::on_output(output, layout)
|
MinimalCombinedArtifacts::on_output(output, layout)
|
||||||
|
@ -678,7 +688,7 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
|
||||||
tracing::trace!("Fallback to hardhat artifact deserialization");
|
tracing::trace!("Fallback to hardhat artifact deserialization");
|
||||||
let artifact = serde_json::from_str::<HardhatArtifact>(&content)?;
|
let artifact = serde_json::from_str::<HardhatArtifact>(&content)?;
|
||||||
tracing::trace!("successfully deserialized hardhat artifact");
|
tracing::trace!("successfully deserialized hardhat artifact");
|
||||||
Ok(artifact.into_compact_contract())
|
Ok(artifact.into_contract_bytecode())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
//! Hardhat support
|
//! Hardhat support
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
artifacts::{BytecodeObject, CompactContract, Contract, Offsets},
|
artifacts::{
|
||||||
|
Bytecode, BytecodeObject, CompactContract, CompactContractBytecode, Contract,
|
||||||
|
ContractBytecode, DeployedBytecode, Offsets,
|
||||||
|
},
|
||||||
error::{Result, SolcError},
|
error::{Result, SolcError},
|
||||||
ArtifactOutput, CompilerOutput, ProjectPathsConfig,
|
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
|
/// Hardhat style artifacts handler
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct HardhatArtifacts;
|
pub struct HardhatArtifacts;
|
||||||
|
|
|
@ -918,11 +918,11 @@ impl<T: ArtifactOutput + 'static> ProjectCompileOutput<T> {
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use std::collections::BTreeMap;
|
/// use std::collections::BTreeMap;
|
||||||
/// use ethers_solc::artifacts::CompactContract;
|
/// use ethers_solc::artifacts::CompactContractBytecode;
|
||||||
/// use ethers_solc::Project;
|
/// use ethers_solc::Project;
|
||||||
///
|
///
|
||||||
/// let project = Project::builder().build().unwrap();
|
/// 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)>> {
|
pub fn into_artifacts(mut self) -> Box<dyn Iterator<Item = (String, T::Artifact)>> {
|
||||||
let artifacts = self.artifacts.into_iter().filter_map(|(path, art)| {
|
let artifacts = self.artifacts.into_iter().filter_map(|(path, art)| {
|
||||||
|
|
Loading…
Reference in New Issue