Skip to content

Commit

Permalink
Add flag in codegen to ignore errors for unhandled types (#350)
Browse files Browse the repository at this point in the history
* Add --continue-on-error flag to codegen for skipping unhandled data types

* Use solc version defined in config

* Fix codegen log for unhandled array types

* Log solc compilation errors

---------

Co-authored-by: Dhruv Srivastava <[email protected]>
  • Loading branch information
nikugogoi and dafaqdhruv authored Apr 6, 2023
1 parent 8c92851 commit 754db31
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 21 deletions.
33 changes: 31 additions & 2 deletions packages/codegen/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@

import solc from 'solc';

interface Solc {
compile(input: string): any;
}

/**
* Compiles the given contract using solc and returns resultant artifacts.
* @param contractContent Contents of the contract file to be compiled.
* @param contractFileName Input contract file name.
* @param contractName Name of the main contract in the contract file.
*/
export function generateArtifacts (contractContent: string, contractFileName: string, contractName: string): { abi: any[], storageLayout: any } {
export async function generateArtifacts (contractContent: string, contractFileName: string, contractName: string, solcVersion: string): Promise<{ abi: any[], storageLayout: any }> {
const input: any = {
language: 'Solidity',
sources: {},
Expand All @@ -27,6 +31,31 @@ export function generateArtifacts (contractContent: string, contractFileName: st
content: contractContent
};

const solcInstance = (solcVersion === undefined) ? solc : await getSolcByVersion(solcVersion);
const compiledContract = JSON.parse(solcInstance.compile(JSON.stringify(input)));

if (compiledContract.errors?.length) {
compiledContract.errors.forEach((error: any) => {
if (error.severity === 'error') {
throw new Error(error.formattedMessage);
}

console.log(`${error.severity}: ${error.formattedMessage}`);
});
}

// Get artifacts for the required contract.
return JSON.parse(solc.compile(JSON.stringify(input))).contracts[contractFileName][contractName];
return compiledContract.contracts[contractFileName][contractName];
}

async function getSolcByVersion (solcVersion: string): Promise<Solc> {
return new Promise((resolve, reject) => {
solc.loadRemoteVersion(solcVersion, (err: any, solcInstance: Solc | Promise<any>) => {
if (err) {
reject(err);
} else {
resolve(solcInstance);
}
});
});
}
16 changes: 13 additions & 3 deletions packages/codegen/src/generate-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ const main = async (): Promise<void> => {
describe: 'Watcher generation config file path (yaml)',
type: 'string'
})
.option('continue-on-error', {
alias: 'e',
demandOption: false,
default: false,
describe: 'Continue generating watcher if unhandled types encountered',
type: 'boolean'
})
.argv;

const config = getConfig(path.resolve(argv['config-file']));
Expand Down Expand Up @@ -83,10 +90,11 @@ const main = async (): Promise<void> => {
// Generate artifacts from contract.
const inputFileName = path.basename(inputFile, '.sol');

const { abi, storageLayout } = generateArtifacts(
const { abi, storageLayout } = await generateArtifacts(
contractData.contractString,
`${inputFileName}.sol`,
contractData.contractName
contractData.contractName,
config.solc
);

contractData.contractAbi = abi;
Expand All @@ -96,7 +104,8 @@ const main = async (): Promise<void> => {
contracts.push(contractData);
}

const visitor = new Visitor();
const continueOnError = argv['continue-on-error'];
const visitor = new Visitor(continueOnError);

parseAndVisit(visitor, contracts, config.mode);

Expand Down Expand Up @@ -379,6 +388,7 @@ function getConfig (configFile: string): any {
mode: inputConfig.mode || MODE_ALL,
kind: inputConfig.kind || KIND_ACTIVE,
port: inputConfig.port || DEFAULT_PORT,
solc: inputConfig.solc,
flatten,
subgraphPath,
subgraphConfig
Expand Down
53 changes: 37 additions & 16 deletions packages/codegen/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ export class Visitor {
_database: Database;
_client: Client;
_types: Types;
_continueOnError: boolean;

_contract?: { name: string, kind: string };

constructor () {
constructor (continueOnErrorFlag = false) {
this._schema = new Schema();
this._resolvers = new Resolvers();
this._indexer = new Indexer();
this._entity = new Entity();
this._database = new Database();
this._client = new Client();
this._types = new Types();
this._continueOnError = continueOnErrorFlag;
}

setContract (name: string, kind: string): void {
Expand All @@ -56,25 +58,44 @@ export class Visitor {
return { name: item.name, type: item.typeName.name };
});

const typeName = node.returnParameters[0].typeName;
let errorMessage = '';

// TODO Handle user defined type return.
if (typeName.type === 'UserDefinedTypeName') {
// Skip in case of UserDefinedTypeName.
return;
const typeName = node.returnParameters[0].typeName;
switch (typeName.type) {
case 'ElementaryTypeName': {
const returnType = typeName.name;

this._schema.addQuery(name, params, returnType);
this._resolvers.addQuery(name, params, returnType);
this._entity.addQuery(name, params, returnType);
this._database.addQuery(name, params, returnType);
this._client.addQuery(name, params, returnType);

assert(this._contract);
this._indexer.addQuery(this._contract.name, MODE_ETH_CALL, name, params, returnType);

break;
}
case 'UserDefinedTypeName':
errorMessage = `No support in codegen for user defined return type from method "${node.name}"`;
break;

case 'ArrayTypeName':
errorMessage = `No support in codegen for return type "${typeName.baseTypeName.name}[]" from method "${node.name}"`;
break;

default:
errorMessage = `No support in codegen for return type "${typeName.type}" from method "${node.name}"`;
}

// TODO Handle multiple return parameters and array return type.
const returnType = typeName.name;
if (errorMessage !== '') {
if (this._continueOnError) {
console.log(errorMessage);
return;
}

this._schema.addQuery(name, params, returnType);
this._resolvers.addQuery(name, params, returnType);
this._entity.addQuery(name, params, returnType);
this._database.addQuery(name, params, returnType);
this._client.addQuery(name, params, returnType);

assert(this._contract);
this._indexer.addQuery(this._contract.name, MODE_ETH_CALL, name, params, returnType);
throw new Error(errorMessage);
}
}
}

Expand Down

0 comments on commit 754db31

Please sign in to comment.