feat(solc): more artifact trait functions (#1057)

* style: split artifacts mod and create contract and bytecode mods

* chore: rustfmt

* feat(solc): more artifact trait functions

* feat: add missing impl
This commit is contained in:
Matthias Seitz 2022-03-17 20:48:55 +01:00 committed by GitHub
parent 65b1751cf8
commit d1f46f4c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 173 additions and 7 deletions

View File

@ -5,13 +5,13 @@ use crate::{
bytecode::{CompactBytecode, CompactDeployedBytecode}, bytecode::{CompactBytecode, CompactDeployedBytecode},
contract::{CompactContract, CompactContractBytecode, Contract}, contract::{CompactContract, CompactContractBytecode, Contract},
output_selection::{ContractOutputSelection, EvmOutputSelection, EwasmOutputSelection}, output_selection::{ContractOutputSelection, EvmOutputSelection, EwasmOutputSelection},
CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata, Offsets, Settings, CompactContractBytecodeCow, CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata,
StorageLayout, UserDoc, Offsets, Settings, StorageLayout, UserDoc,
}, },
ArtifactOutput, SolcConfig, SolcError, ArtifactOutput, SolcConfig, SolcError,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fs, path::Path}; use std::{borrow::Cow, collections::BTreeMap, fs, path::Path};
/// Represents the `Artifact` that `ConfigurableArtifacts` emits. /// Represents the `Artifact` that `ConfigurableArtifacts` emits.
/// ///
@ -87,6 +87,16 @@ impl From<ConfigurableContractArtifact> for CompactContract {
} }
} }
impl<'a> From<&'a ConfigurableContractArtifact> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a ConfigurableContractArtifact) -> Self {
CompactContractBytecodeCow {
abi: artifact.abi.as_ref().map(|abi| Cow::Borrowed(&abi.abi)),
bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed),
deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed),
}
}
}
/// An `Artifact` implementation that can be configured to include additional content and emit /// An `Artifact` implementation that can be configured to include additional content and emit
/// additional files /// additional files
/// ///

View File

@ -8,13 +8,17 @@ use ethers_core::{abi::Abi, types::Bytes};
use semver::Version; use semver::Version;
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use std::{ use std::{
borrow::Cow,
collections::btree_map::BTreeMap, collections::btree_map::BTreeMap,
fmt, fs, io, fmt, fs, io,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
mod configurable; mod configurable;
use crate::artifacts::contract::{CompactContract, CompactContractBytecode, Contract}; use crate::artifacts::{
contract::{CompactContract, CompactContractBytecode, Contract},
BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode,
};
pub use configurable::*; pub use configurable::*;
/// Represents unique artifact metadata for identifying artifacts on output /// Represents unique artifact metadata for identifying artifacts on output
@ -290,6 +294,29 @@ pub trait Artifact {
/// 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>);
/// Consumes the type and returns the [Abi]
fn into_abi(self) -> Option<Abi>
where
Self: Sized,
{
self.into_parts().0
}
/// Consumes the type and returns the `bytecode`
fn into_bytecode_bytes(self) -> Option<Bytes>
where
Self: Sized,
{
self.into_parts().1
}
/// Consumes the type and returns the `deployed bytecode`
fn into_deployed_bytecode_bytes(self) -> Option<Bytes>
where
Self: Sized,
{
self.into_parts().2
}
/// Same as [`Self::into_parts()`] but returns `Err` if an element is `None` /// Same as [`Self::into_parts()`] but returns `Err` if an element is `None`
fn try_into_parts(self) -> Result<(Abi, Bytes, Bytes)> fn try_into_parts(self) -> Result<(Abi, Bytes, Bytes)>
where where
@ -303,11 +330,67 @@ pub trait Artifact {
deployed_bytecode.ok_or_else(|| SolcError::msg("deployed bytecode missing"))?, deployed_bytecode.ok_or_else(|| SolcError::msg("deployed bytecode missing"))?,
)) ))
} }
/// Returns the reference of container type for abi, compact bytecode and deployed bytecode if
/// available
fn get_contract_bytecode(&self) -> CompactContractBytecodeCow;
/// Returns the reference to the `bytecode`
fn get_bytecode(&self) -> Option<Cow<CompactBytecode>> {
self.get_contract_bytecode().bytecode
}
/// Returns the reference to the `bytecode` object
fn get_bytecode_object(&self) -> Option<Cow<BytecodeObject>> {
let val = match self.get_bytecode()? {
Cow::Borrowed(b) => Cow::Borrowed(&b.object),
Cow::Owned(b) => Cow::Owned(b.object),
};
Some(val)
}
/// Returns the bytes of the `bytecode` object
fn get_bytecode_bytes(&self) -> Option<Cow<Bytes>> {
let val = match self.get_bytecode_object()? {
Cow::Borrowed(b) => Cow::Borrowed(b.as_bytes()?),
Cow::Owned(b) => Cow::Owned(b.into_bytes()?),
};
Some(val)
}
/// Returns the reference to the `deployedBytecode`
fn get_deployed_bytecode(&self) -> Option<Cow<CompactDeployedBytecode>> {
self.get_contract_bytecode().deployed_bytecode
}
/// Returns the reference to the `bytecode` object
fn get_deployed_bytecode_object(&self) -> Option<Cow<BytecodeObject>> {
let val = match self.get_deployed_bytecode()? {
Cow::Borrowed(b) => Cow::Borrowed(&b.bytecode.as_ref()?.object),
Cow::Owned(b) => Cow::Owned(b.bytecode?.object),
};
Some(val)
}
/// Returns the bytes of the `deployed bytecode` object
fn get_deployed_bytecode_bytes(&self) -> Option<Cow<Bytes>> {
let val = match self.get_deployed_bytecode_object()? {
Cow::Borrowed(b) => Cow::Borrowed(b.as_bytes()?),
Cow::Owned(b) => Cow::Owned(b.into_bytes()?),
};
Some(val)
}
/// Returns the reference to the [Abi] if available
fn get_abi(&self) -> Option<Cow<Abi>> {
self.get_contract_bytecode().abi
}
} }
impl<T> Artifact for T impl<T> Artifact for T
where where
T: Into<CompactContractBytecode> + Into<CompactContract>, T: Into<CompactContractBytecode> + Into<CompactContract>,
for<'a> &'a T: Into<CompactContractBytecodeCow<'a>>,
{ {
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();
@ -325,6 +408,10 @@ where
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()
} }
fn get_contract_bytecode(&self) -> CompactContractBytecodeCow {
self.into()
}
} }
/// Handler invoked with the output of `solc` /// Handler invoked with the output of `solc`

View File

@ -221,6 +221,14 @@ impl BytecodeObject {
BytecodeObject::Unlinked(_) => None, BytecodeObject::Unlinked(_) => None,
} }
} }
/// Returns the number of bytes of the fully linked bytecode
///
/// Returns `0` if this object is unlinked.
pub fn bytes_len(&self) -> usize {
self.as_bytes().map(|b| b.as_ref().len()).unwrap_or_default()
}
/// Returns a reference to the underlying `String` if the object is unlinked /// Returns a reference to the underlying `String` if the object is unlinked
pub fn as_str(&self) -> Option<&str> { pub fn as_str(&self) -> Option<&str> {
match self { match self {

View File

@ -8,7 +8,7 @@ use crate::artifacts::{
}; };
use ethers_core::{abi::Contract as Abi, types::Bytes}; use ethers_core::{abi::Contract as Abi, types::Bytes};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryFrom}; use std::{borrow::Cow, collections::BTreeMap, convert::TryFrom};
/// Represents a compiled solidity contract /// Represents a compiled solidity contract
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -41,6 +41,24 @@ pub struct Contract {
pub ir_optimized: Option<String>, pub ir_optimized: Option<String>,
} }
impl<'a> From<&'a Contract> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a Contract) -> Self {
let (bytecode, deployed_bytecode) = if let Some(ref evm) = artifact.evm {
(
evm.bytecode.clone().map(Into::into).map(Cow::Owned),
evm.deployed_bytecode.clone().map(Into::into).map(Cow::Owned),
)
} else {
(None, None)
};
CompactContractBytecodeCow {
abi: artifact.abi.as_ref().map(|abi| Cow::Borrowed(&abi.abi)),
bytecode,
deployed_bytecode,
}
}
}
/// 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
@ -143,6 +161,16 @@ impl CompactContractBytecode {
} }
} }
impl<'a> From<&'a CompactContractBytecode> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a CompactContractBytecode) -> Self {
CompactContractBytecodeCow {
abi: artifact.abi.as_ref().map(Cow::Borrowed),
bytecode: artifact.bytecode.as_ref().map(Cow::Borrowed),
deployed_bytecode: artifact.deployed_bytecode.as_ref().map(Cow::Borrowed),
}
}
}
impl From<Contract> for CompactContractBytecode { impl From<Contract> for CompactContractBytecode {
fn from(c: Contract) -> Self { fn from(c: Contract) -> Self {
let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm { let (bytecode, deployed_bytecode) = if let Some(evm) = c.evm {
@ -180,6 +208,17 @@ impl From<CompactContractBytecode> for ContractBytecode {
} }
} }
/// A [CompactContractBytecode] that is either owns or borrows its content
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CompactContractBytecodeCow<'a> {
pub abi: Option<Cow<'a, Abi>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bytecode: Option<Cow<'a, CompactBytecode>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deployed_bytecode: Option<Cow<'a, CompactDeployedBytecode>>,
}
/// 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
@ -311,6 +350,17 @@ impl From<serde_json::Value> for CompactContract {
} }
} }
impl<'a> From<&'a serde_json::Value> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a serde_json::Value) -> Self {
let c = CompactContractBytecode::from(artifact.clone());
CompactContractBytecodeCow {
abi: c.abi.map(Cow::Owned),
bytecode: c.bytecode.map(Cow::Owned),
deployed_bytecode: c.deployed_bytecode.map(Cow::Owned),
}
}
}
impl From<serde_json::Value> for CompactContractBytecode { impl From<serde_json::Value> for CompactContractBytecode {
fn from(val: serde_json::Value) -> Self { fn from(val: serde_json::Value) -> Self {
serde_json::from_value(val).unwrap_or_default() serde_json::from_value(val).unwrap_or_default()

View File

@ -4,12 +4,12 @@ use crate::{
artifacts::{ artifacts::{
bytecode::{Bytecode, BytecodeObject, DeployedBytecode}, bytecode::{Bytecode, BytecodeObject, DeployedBytecode},
contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode}, contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode},
LosslessAbi, Offsets, CompactContractBytecodeCow, LosslessAbi, Offsets,
}, },
ArtifactOutput, ArtifactOutput,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::btree_map::BTreeMap; use std::{borrow::Cow, collections::btree_map::BTreeMap};
const HH_ARTIFACT_VERSION: &str = "hh-sol-artifact-1"; const HH_ARTIFACT_VERSION: &str = "hh-sol-artifact-1";
@ -41,6 +41,17 @@ pub struct HardhatArtifact {
pub deployed_link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>, pub deployed_link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
} }
impl<'a> From<&'a HardhatArtifact> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a HardhatArtifact) -> Self {
let c: ContractBytecode = artifact.clone().into();
CompactContractBytecodeCow {
abi: Some(Cow::Borrowed(&artifact.abi.abi)),
bytecode: c.bytecode.map(|b| Cow::Owned(b.into())),
deployed_bytecode: c.deployed_bytecode.map(|b| Cow::Owned(b.into())),
}
}
}
impl From<HardhatArtifact> for CompactContract { impl From<HardhatArtifact> for CompactContract {
fn from(artifact: HardhatArtifact) -> Self { fn from(artifact: HardhatArtifact) -> Self {
CompactContract { CompactContract {