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},
contract::{CompactContract, CompactContractBytecode, Contract},
output_selection::{ContractOutputSelection, EvmOutputSelection, EwasmOutputSelection},
CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata, Offsets, Settings,
StorageLayout, UserDoc,
CompactContractBytecodeCow, CompactEvm, DevDoc, Ewasm, GasEstimates, LosslessAbi, Metadata,
Offsets, Settings, StorageLayout, UserDoc,
},
ArtifactOutput, SolcConfig, SolcError,
};
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.
///
@ -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
/// additional files
///

View File

@ -8,13 +8,17 @@ use ethers_core::{abi::Abi, types::Bytes};
use semver::Version;
use serde::{de::DeserializeOwned, Serialize};
use std::{
borrow::Cow,
collections::btree_map::BTreeMap,
fmt, fs, io,
path::{Path, PathBuf},
};
mod configurable;
use crate::artifacts::contract::{CompactContract, CompactContractBytecode, Contract};
use crate::artifacts::{
contract::{CompactContract, CompactContractBytecode, Contract},
BytecodeObject, CompactBytecode, CompactContractBytecodeCow, CompactDeployedBytecode,
};
pub use configurable::*;
/// 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
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`
fn try_into_parts(self) -> Result<(Abi, Bytes, Bytes)>
where
@ -303,11 +330,67 @@ pub trait Artifact {
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
where
T: Into<CompactContractBytecode> + Into<CompactContract>,
for<'a> &'a T: Into<CompactContractBytecodeCow<'a>>,
{
fn into_inner(self) -> (Option<Abi>, Option<Bytes>) {
let artifact = self.into_compact_contract();
@ -325,6 +408,10 @@ where
fn into_parts(self) -> (Option<Abi>, Option<Bytes>, Option<Bytes>) {
self.into_compact_contract().into_parts()
}
fn get_contract_bytecode(&self) -> CompactContractBytecodeCow {
self.into()
}
}
/// Handler invoked with the output of `solc`

View File

@ -221,6 +221,14 @@ impl BytecodeObject {
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
pub fn as_str(&self) -> Option<&str> {
match self {

View File

@ -8,7 +8,7 @@ use crate::artifacts::{
};
use ethers_core::{abi::Contract as Abi, types::Bytes};
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryFrom};
use std::{borrow::Cow, collections::BTreeMap, convert::TryFrom};
/// Represents a compiled solidity contract
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -41,6 +41,24 @@ pub struct Contract {
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.
///
/// 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 {
fn from(c: Contract) -> Self {
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.
///
/// 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 {
fn from(val: serde_json::Value) -> Self {
serde_json::from_value(val).unwrap_or_default()

View File

@ -4,12 +4,12 @@ use crate::{
artifacts::{
bytecode::{Bytecode, BytecodeObject, DeployedBytecode},
contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode},
LosslessAbi, Offsets,
CompactContractBytecodeCow, LosslessAbi, Offsets,
},
ArtifactOutput,
};
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";
@ -41,6 +41,17 @@ pub struct HardhatArtifact {
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 {
fn from(artifact: HardhatArtifact) -> Self {
CompactContract {