Skip to content

Commit

Permalink
Refine ain contracts build script and sol artifacts (#2409)
Browse files Browse the repository at this point in the history
* Cleanup ain contract build script

* Minor cleanups

* Minor refinements

* Generate both bytecode and deployed bytecode

* Remove intermediary

* Use deployed_bytecode

* Update for changes

* Fix input scripts and terminology

* Add WIP macros

* Fix up paths

* Remove .json from macro

* Use literal instead of expr

* Fix solc artifact path in tests

* Add macro to get bytecode

* Move solc artifact path to utils

* Fix Python lint

---------

Co-authored-by: Shoham Chakraborty <[email protected]>
  • Loading branch information
prasannavl and shohamc1 authored Sep 6, 2023
1 parent 9fe1d71 commit d7697ce
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 117 deletions.
90 changes: 48 additions & 42 deletions lib/ain-contracts/build.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
use std::{env, fs, path::PathBuf};

use anyhow::format_err;
use anyhow::{bail, Context, Result};
use ethers_solc::{artifacts::Optimizer, Project, ProjectPathsConfig, Solc, SolcConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
// compile solidity project
// configure `root` as our project root
fn main() -> Result<()> {
let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
let solc_path_str = env::var("SOLC_PATH")?;

// If TARGET_DIR is set, which we do from Makefile, uses that instead of OUT_DIR.
// Otherwise, use the path for OUT_DIR that cargo sets, as usual.
// Reason: Currently setting --out-dir is nightly only, so there's no way to get OUT_DIR
// out of cargo reliably for pointing deps determinisitcally.
let target_dir: PathBuf = PathBuf::from(env::var("CARGO_TARGET_DIR").or(env::var("OUT_DIR"))?);
let solc_artifact_dir = target_dir.join("sol_artifacts");

// Solidity project root and contract names relative to our project
let contracts = vec![
("dfi_intrinsics", "DFIIntrinsics"),
("dst20", "DST20"),
("system_reserved", "SystemReservedContract"),
("dfi_reserved", "DFIReserved"),
("transfer_domain", "TransferDomain"),
("dst20", "DST20"),
];

for (file_path, contract_name) in contracts {
let solc = Solc::new(env::var("SOLC_PATH")?);
let output_path = env::var("CARGO_TARGET_DIR")?;
let root = PathBuf::from(file_path);
if !root.exists() {
return Err("Project root {root:?} does not exists!".into());
for (sol_project_name, contract_name) in contracts {
let solc = Solc::new(&solc_path_str);

let sol_project_root = manifest_path.join(sol_project_name);
if !sol_project_root.exists() {
bail!("Solidity project missing: {sol_project_root:?}");
}

let paths = ProjectPathsConfig::builder()
.root(&root)
.sources(&root)
.root(&sol_project_root)
.sources(&sol_project_root)
.build()?;

let mut solc_config = SolcConfig::builder().build();
Expand All @@ -41,37 +50,34 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.set_auto_detect(true)
.no_artifacts()
.build()?;
let output = project.compile().unwrap();

let output = project.compile()?;
let artifacts = output.into_artifacts();
let sol_project_outdir = solc_artifact_dir.join(sol_project_name);

for (id, artifact) in artifacts {
if id.name == contract_name {
let abi = artifact.abi.ok_or_else(|| format_err!("ABI not found"))?;
let deployed_bytecode = artifact
.deployed_bytecode
.expect("No deployed_bytecode found");

let bytecode = artifact.bytecode.expect("No bytecode found");

fs::create_dir_all(format!("{output_path}/ain_contracts/{file_path}"))?;
fs::write(
PathBuf::from(format!(
"{output_path}/ain_contracts/{file_path}/bytecode.json"
)),
serde_json::to_string(&deployed_bytecode)
.unwrap()
.as_bytes(),
)?;
fs::write(
PathBuf::from(format!(
"{output_path}/ain_contracts/{file_path}/input.json"
)),
serde_json::to_string(&bytecode).unwrap().as_bytes(),
)?;
fs::write(
PathBuf::from(format!("{output_path}/ain_contracts/{file_path}/abi.json")),
serde_json::to_string(&abi).unwrap().as_bytes(),
)?;
if id.name != contract_name {
continue;
}

let abi = artifact.abi.context("ABI not found")?;
let bytecode = artifact.bytecode.context("Bytecode not found")?;
let deployed_bytecode = artifact
.deployed_bytecode
.context("Deployed bytecode not found")?;

let items = [
("abi.json", serde_json::to_string(&abi)?),
("bytecode.json", serde_json::to_string(&bytecode)?),
(
"deployed_bytecode.json",
serde_json::to_string(&deployed_bytecode)?,
),
];

fs::create_dir_all(&sol_project_outdir)?;
for (file_name, contents) in items {
fs::write(sol_project_outdir.join(file_name), contents.as_bytes())?
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@

pragma solidity ^0.8.0;

contract SystemReservedContract {
}
contract DFIReserved {}
File renamed without changes.
60 changes: 40 additions & 20 deletions lib/ain-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ use sp_core::{Blake2Hasher, Hasher};

pub type Result<T> = std::result::Result<T, anyhow::Error>;

macro_rules! solc_artifact_path {
($project_name:literal, $artifact:literal) => {
concat!(
env!("CARGO_TARGET_DIR"),
"/sol_artifacts/",
$project_name,
"/",
$artifact
)
};
}

macro_rules! solc_artifact_content_str {
($project_name:literal, $artifact:literal) => {
include_str!(solc_artifact_path!($project_name, $artifact))
};
}

macro_rules! solc_artifact_bytecode_str {
($project_name:literal, $artifact:literal) => {
get_bytecode(solc_artifact_content_str!($project_name, $artifact)).unwrap()
};
}

fn get_bytecode(input: &str) -> Result<Vec<u8>> {
let bytecode_json: serde_json::Value = serde_json::from_str(input)?;
let bytecode_raw = bytecode_json["object"]
Expand Down Expand Up @@ -46,10 +70,7 @@ pub struct FixedContract {

lazy_static::lazy_static! {
pub static ref INTRINSIC_CONTRACT: FixedContract = {
let bytecode = get_bytecode(include_str!(concat!(
env!("CARGO_TARGET_DIR"),
"/ain_contracts/dfi_intrinsics/bytecode.json"
))).unwrap();
let bytecode = solc_artifact_bytecode_str!("dfi_intrinsics", "deployed_bytecode.json");

FixedContract {
contract: Contract {
Expand All @@ -65,14 +86,14 @@ lazy_static::lazy_static! {
};

pub static ref TRANSFERDOMAIN_CONTRACT: FixedContract = {
let bytecode = get_bytecode(include_str!(concat!(
env!("CARGO_TARGET_DIR"),
"/ain_contracts/transfer_domain/bytecode.json"
))).unwrap();
let input = get_bytecode(include_str!(concat!(
env!("CARGO_TARGET_DIR"),
"/ain_contracts/transfer_domain/input.json"
))).unwrap();
// Note that input, bytecode, and deployed bytecode is used in confusing ways since
// deployedBytecode was exposed as bytecode earlier in build script.
// TODO: Refactor terminology to align with the source of truth.
let bytecode = solc_artifact_bytecode_str!("transfer_domain", "deployed_bytecode.json");
let input = solc_artifact_bytecode_str!(
"transfer_domain",
"bytecode.json"
);

FixedContract {
contract: Contract {
Expand All @@ -88,10 +109,9 @@ lazy_static::lazy_static! {
};

pub static ref DST20_CONTRACT: Contract = {
let bytecode = get_bytecode(include_str!(concat!(
env!("CARGO_TARGET_DIR"),
"/ain_contracts/dst20/bytecode.json"
))).unwrap();
let bytecode = solc_artifact_bytecode_str!(
"dst20", "deployed_bytecode.json"
);
let input = get_bytecode(include_str!(
"../dst20/input.json"
)).unwrap();
Expand All @@ -104,10 +124,10 @@ lazy_static::lazy_static! {
};

pub static ref RESERVED_CONTRACT: Contract = {
let bytecode = get_bytecode(include_str!(concat!(
env!("CARGO_TARGET_DIR"),
"/ain_contracts/system_reserved/bytecode.json"
))).unwrap();
let bytecode = solc_artifact_bytecode_str!(
"dfi_reserved",
"deployed_bytecode.json"
);

Contract {
codehash: Blake2Hasher::hash(&bytecode),
Expand Down
56 changes: 18 additions & 38 deletions test/functional/feature_dst20.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
import math
import json
import time
import os
from decimal import Decimal

from test_framework.evm_key_pair import EvmKeyPair
from test_framework.test_framework import DefiTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
get_solc_artifact_path,
)


class DST20(DefiTestFramework):
Expand Down Expand Up @@ -793,48 +796,25 @@ def run_test(self):
)

# Contract ABI
if os.getenv("BUILD_DIR"):
build_dir = os.getenv("BUILD_DIR")
self.abi = open(
f"{build_dir}/ain_contracts/dst20/abi.json",
self.abi = open(
get_solc_artifact_path("dst20", "abi.json"),
"r",
encoding="utf8",
).read()
self.bytecode = json.loads(
open(
get_solc_artifact_path("dst20", "deployed_bytecode.json"),
"r",
encoding="utf8",
).read()
self.bytecode = json.loads(
open(
f"{build_dir}/ain_contracts/dst20/bytecode.json",
"r",
encoding="utf8",
).read()
)["object"]
self.reserved_bytecode = json.loads(
open(
f"{build_dir}/ain_contracts/system_reserved/bytecode.json",
"r",
encoding="utf8",
).read()
)["object"]
else:
# fall back to using relative path
self.abi = open(
f"{os.path.dirname(__file__)}/../../build/lib/target/ain_contracts/dst20/abi.json",
)["object"]
self.reserved_bytecode = json.loads(
open(
get_solc_artifact_path("dfi_reserved", "deployed_bytecode.json"),
"r",
encoding="utf8",
).read()
self.bytecode = json.loads(
open(
f"{os.path.dirname(__file__)}/../../build/lib/target/ain_contracts/dst20/bytecode.json",
"r",
encoding="utf8",
).read()
)["object"]
self.reserved_bytecode = json.loads(
open(
f"{os.path.dirname(__file__)}/../../build/lib/target/ain_contracts/system_reserved/bytecode.json",
"r",
encoding="utf8",
).read()
)["object"]
)["object"]

# Generate chain
self.node.generate(150)
Expand Down
22 changes: 7 additions & 15 deletions test/functional/feature_evm_dfi_intrinsics.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""Test DFI intrinsics contract"""

import os
import json

from test_framework.test_framework import DefiTestFramework
from test_framework.util import assert_equal
from test_framework.util import assert_equal, get_solc_artifact_path


class DFIIntrinsicsTest(DefiTestFramework):
Expand Down Expand Up @@ -49,7 +48,7 @@ def run_test(self):
# check reserved address space
reserved_bytecode = json.loads(
open(
f"{os.path.dirname(__file__)}/../../build/lib/target/ain_contracts/system_reserved/bytecode.json",
get_solc_artifact_path("dfi_reserved", "deployed_bytecode.json"),
"r",
encoding="utf8",
).read()
Expand All @@ -72,18 +71,11 @@ def run_test(self):
)

# check counter contract
if os.getenv("BUILD_DIR"):
abi = open(
f"{os.getenv('BUILD_DIR')}/ain_contracts/dfi_intrinsics/abi.json",
"r",
encoding="utf8",
).read()
else:
abi = open(
f"{os.path.dirname(__file__)}/../../build/lib/target/ain_contracts/dfi_intrinsics/abi.json",
"r",
encoding="utf8",
).read()
abi = open(
get_solc_artifact_path("dfi_intrinsics", "abi.json"),
"r",
encoding="utf8",
).read()

counter_contract = node.w3.eth.contract(
address=node.w3.to_checksum_address(
Expand Down
8 changes: 8 additions & 0 deletions test/functional/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,3 +911,11 @@ def token_index_in_account(account, symbol):
if symbol in account[id]:
return id
return -1


# Web3 functions
#############################


def get_solc_artifact_path(contract: str, file_name: str) -> str:
return f"{os.path.dirname(__file__)}/../../../build/lib/target/sol_artifacts/{contract}/{file_name}"

0 comments on commit d7697ce

Please sign in to comment.