Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Support compilation of ethpm build deps - one level deep
Browse files Browse the repository at this point in the history
  • Loading branch information
njgheorghita committed Mar 10, 2020
1 parent b533406 commit 6f9a193
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 104 deletions.
216 changes: 125 additions & 91 deletions packages/core/lib/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const { isAddress } = require("web3-utils");
const path = require("path");
const fs = require("fs");
const ENSJS = require("ethereum-ens");
const TruffleContractSchema = require("@truffle/contract-schema");

SUPPORTED_CHAIN_IDS = {
1: "mainnet",
Expand Down Expand Up @@ -47,6 +48,7 @@ const Package = {
done(new TruffleError(err.message));
}

// Add some nicer logging to let user know whats going on
// Parse ethpm uri
let ethpmUri;
try {
Expand All @@ -70,7 +72,7 @@ const Package = {
);
const provider = new Web3.providers.HttpProvider(infuraUri, {
keepAlive: true
}); // do we need/want keepAlive?
});

// Resolve ENS names in ethpm uri
if (!isAddress(ethpmUri.address)) {
Expand All @@ -81,7 +83,6 @@ const Package = {
)
);
}
// default ens in configDefaults? breaking!
if (options.ens.enabled === false) {
done(
new TruffleError(
Expand Down Expand Up @@ -116,20 +117,19 @@ const Package = {
}
});
} catch (err) {
done(new TruffleError(`Invalid config: ${err.message}`));
done(new TruffleError(`Unable to configure ethPM: ${err.message}`));
}

// Validate target package is available on connected registry
const availablePackages = await ethpm.registries.packages();
if (!availablePackages.includes(ethpmUri.packageName)) {
done(
new TruffleError(
"Package: " +
ethpmUri.packageName +
", not found on registry at address: " +
ethpmUri.address +
". Available packages include: " +
availablePackages
`Package: ${
ethpmUri.packageName
}, not found on registry at address: ${
ethpmUri.address
}. Available packages include: ${availablePackages}`
)
);
}
Expand Down Expand Up @@ -159,7 +159,7 @@ const Package = {
await Contracts.compile(options.with({ all: true, quiet: true }));
const artifactor = new Artifactor(options.contracts_build_directory);

// w/ blockchainUri => network id
// convert blockchainUri => network id
const normalizedDeployments = {};

if (ethpmPackage.deployments) {
Expand Down Expand Up @@ -191,26 +191,42 @@ const Package = {
}
// WORKS BUT HAS INCORRECT PROVIDER?
const validContractSchema = {
abi: contractData.abi,
contractName: contractData.contractName,
compiler: {
name: contractData.compiler.name,
version: contractData.compiler.version
}
//networks: contractDeployments,
//bytecode: contractData.deploymentBytecode,
//deployedBytecode: contractData.runtimeBytecode,
//test: contractData.test
// prob
// contractName: contractData.contractName,
...(contractData.abi && { abi: contractData.abi }),
...(contractData.contractName && {
contractName: contractData.contractName
}),
...(contractData.compiler && {
compiler: {
...(contractData.compiler.name && {
name: contractData.compiler.name
}),
...(contractData.compiler.version && {
version: contractData.compiler.version
})
}
}),
// idt these support linkrefs
...(contractData.runtimeBytecode &&
contractData.runtimeBytecode.bytecode && {
deployedBytecode: contractData.runtimeBytecode.bytecode
}),
...(contractData.deploymentBytecode &&
contractData.deploymentBytecode.bytecode && {
bytecode: contractData.deploymentBytecode.bytecode
}),
...(contractDeployments && { networks: contractDeployments })
// source: sources?
// no natspec - just devdoc/userdoc
// how to only include a field if defined?
// contract-schema doesn't define devdoc/userdoc but artifacts have it - can we include?
};
// validate against actual contract schema
// seems like abi validation is too strict / outdated?
try {
await TruffleContractSchema.validate(validContractSchema);
} catch (err) {
done(new TruffleError(`ethPM package import error: ${err.message}`));
}
await artifactor.save(validContractSchema);
}
options.logger.log("done storing artifacts");
options.logger.log("Saved artifacts.");
done();
},

Expand All @@ -235,38 +251,45 @@ const Package = {
} catch (err) {
done(new TruffleError(err.message));
}

// validate is setup with mnemonic?
// validate mnemonic has publishing rights for options.registry?

const registryURI = new EthpmURI(options.ethpm.registry);
const registryProviderURI = getInfuraEndpointForChainId(
registryURI.chainId,
options.ethpm.infura_key
options.ethpm.infuraKey
);
const registryProvider = new Web3.providers.HttpProvider(
registryProviderURI,
{ keepAlive: true }
); // do we need/want keepAlive?
const seededProvider = options.networks.ropsten.provider();
registryProvider; // bad - what to do about provider

let ethpm = await EthPM.configure({
manifests: "ethpm/manifests/v2",
storage: "ethpm/storage/ipfs",
registries: "ethpm/registries/web3"
}).connect({
provider: seededProvider, // bad hardcoded provider
registryAddress: registryURI.address,
ipfs: {
host: options.ethpm.ipfsHost,
port: options.ethpm.ipfsPort,
protocol: options.ethpm.ipfsProtocol
}
registryProvider = new Web3.providers.HttpProvider(registryProviderURI, {
keepAlive: true
});

let artifacts = await getPublishableArtifacts(options, ethpm);
console.log("made artifacts");
options.logger.log("Gathering contracts..."); // incorrect place
let ethpm;
try {
ethpm = await EthPM.configure({
manifests: "ethpm/manifests/v2",
storage: "ethpm/storage/ipfs",
registries: "ethpm/registries/web3"
}).connect({
provider: registryProvider, // bad hardcoded provider
registryAddress: registryURI.address,
ipfs: {
host: options.ethpm.ipfsHost,
port: options.ethpm.ipfsPort,
protocol: options.ethpm.ipfsProtocol
}
});
} catch (err) {
done(new TruffleError(`Unable to configure ethPM: ${err.message}`));
}

options.logger.log("Finding publishable artifacts...");
try {
let artifacts = await getPublishableArtifacts(options, ethpm);
console.log(artifacts);
} catch (err) {
done(new TruffleError(`Unable to collect artifacts: ${err}`));
}

// Fetch ethpm.json config
let ethpmConfig;
Expand All @@ -278,17 +301,18 @@ const Package = {
)
);
if (
ethpmConfig.package_name === undefined ||
ethpmConfig.version === undefined
ethpmConfig.packageName === "undefined" ||
ethpmConfig.version === "undefined"
) {
throw new TruffleError(
"Invalid ethpm.json: Must contain a 'package_name' and 'version'."
done(
new TruffleError(
"Invalid ethpm.json: Must contain a 'packageName' and 'version'."
)
);
}
} catch (e) {
throw new TruffleError("Invalid ethpm.json configuration detected.");
} catch (err) {
done(new TruffleError("Invalid ethpm.json configuration detected."));
}
console.log("made ethpm config");

const ethpmFields = {
sources: artifacts.resolvedSources,
Expand All @@ -297,32 +321,36 @@ const Package = {
build_dependencies: {}
};

console.log(`Generating package manifest...`);
const targetConfig = Object.assign(ethpmFields, ethpmConfig);
const pkg = await ethpm.manifests.read(JSON.stringify(targetConfig));
const manifest = await ethpm.manifests.write(pkg);
const manifestURI = await ethpm.storage.write(manifest);

console.log(`made manifest uri: ${manifestURI.href}`);
console.log(`releasing package to ${options.ethpm.registry}`);
console.log(`Releasing package to ${options.ethpm.registry}...`);
await ethpm.registries.registry.methods
.release(ethpmConfig.package_name, ethpmConfig.version, manifestURI.href)
.release(ethpmConfig.packageName, ethpmConfig.version, manifestURI.href)
.send({
from: seededProvider.addresses[0], // this is bad hardcoded account
from: registryProvider.addresses[0], // this is bad hardcoded account
gas: 4712388,
gasPrice: 100000000000
});
options.logger.log(
`Released ${ethpmConfig.package_name}@${
`Released ${ethpmConfig.packageName}@${
ethpmConfig.version
} to registry @ ${options.ethpm.registry}`
} to registry @ ${options.ethpm.registry}` // add link to explorer?
);
//return JSON.parse(manifest); // remove this
}
};

function validateSupportedChainId(chainId) {
if (!(chainId in SUPPORTED_CHAIN_IDS)) {
throw new TruffleError("xxx");
throw new TruffleError(
`Detected chain ID: ${chainId} is not a supported chain id. Supported values include ${Object.keys(
SUPPORTED_CHAIN_IDS
)}`
);
}
}

Expand Down Expand Up @@ -354,55 +382,56 @@ async function getPublishableArtifacts(options, ethpm) {
files = files.filter(file => file.includes(".json"));

if (!files.length) {
var msg =
"Could not locate any publishable artifacts in " +
options.contracts_build_directory +
". " +
"Run `truffle compile` before publishing.";

return new Error(msg);
var msg = `Could not locate any publishable artifacts in ${
options.contracts_build_directory
}. Run "truffle compile" before publishing.`;
return new TruffleError(msg);
}

const fileData = [];
const normData = {};
const artifactsGroupedByNetworkId = {};
const sourcePaths = {};
// group by network id to handle deployments

// group artifacts by network id to ensure consistency when converting networkId => blockchainUri
for (let file of files) {
const fileContents = JSON.parse(
fs.readFileSync(
path.join(options.contracts_build_directory, file),
"utf8"
)
);

sourcePaths[fileContents.sourcePath] = fileContents.source;
const foundNetworkId = Object.keys(fileContents.networks)[0];
if (foundNetworkId in normData) {
normData[foundNetworkId].push(fileContents);
if (foundNetworkId in artifactsGroupedByNetworkId) {
artifactsGroupedByNetworkId[foundNetworkId].push(fileContents);
} else {
normData[foundNetworkId] = [fileContents];
artifactsGroupedByNetworkId[foundNetworkId] = [fileContents];
}
}
// convert network ids to blockchain uri
for (let networkId of Object.keys(normData)) {

const normalizedArtifacts = [];
for (let networkId of Object.keys(artifactsGroupedByNetworkId)) {
// handle artifacts without deployments
if (networkId == "undefined") {
normData[networkId].forEach(item => {
fileData.push(item);
// networkId will be an undefined string not obj
if (networkId === "undefined") {
artifactsGroupedByNetworkId[networkId].forEach(item => {
normalizedArtifacts.push(item);
});
} else {
// convert network ids to blockchain uri
const blockchainUri = await convertNetworkIdToBlockchainUri(
networkId,
options.ethpm.infura_key
options.ethpm.infuraKey
);
normData[networkId].forEach(item => {
artifactsGroupedByNetworkId[networkId].forEach(item => {
delete Object.assign(item.networks, {
[blockchainUri]: item.networks[networkId]
})[networkId];
fileData.push(item);
normalizedArtifacts.push(item);
});
}
}
const parsedArtifacts = parseTruffleArtifacts(fileData);
const parsedArtifacts = parseTruffleArtifacts(normalizedArtifacts);
const sources = await resolveSources(
sourcePaths,
options.contracts_directory,
Expand All @@ -418,13 +447,18 @@ async function getPublishableArtifacts(options, ethpm) {
// handles sources installed via ethpm
async function resolveSources(sourcePaths, contractsDirectory, ethpm) {
const sources = {};
// TODO! how do we include installed pkgs in the publishing process?
// just add as build dependencies? probably
// flatten and include in pkg? probably not
for (let sourcePath of Object.keys(sourcePaths)) {
const ipfsHash = await ethpm.storage.write(sourcePaths[sourcePath]);
// resolve all sources (including ethpm) to absolute contracts dir
const absolute = path.resolve(contractsDirectory, sourcePath);
// resolve all sources to relative path
const resolved = path.relative(contractsDirectory, absolute);
sources[`./${resolved}`] = ipfsHash.href;
if (sourcePath !== "undefined") {
const ipfsHash = await ethpm.storage.write(sourcePaths[sourcePath]);
// resolve all sources (including ethpm) to absolute contracts dir
const absolute = path.resolve(contractsDirectory, sourcePath);
// resolve all sources to relative path
const resolved = path.relative(contractsDirectory, absolute);
sources[`./${resolved}`] = ipfsHash.href;
}
}
return sources;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"debug": "^4.1.0",
"del": "^2.2.0",
"ethereumjs-wallet": "^0.6.2",
"ethpm": "0.1.0-next.17",
"ethpm": "0.1.0-next.18",
"fs-extra": "6.0.1",
"ganache-core": "2.9.2",
"glob": "^7.1.4",
Expand Down
Loading

0 comments on commit 6f9a193

Please sign in to comment.