use docker image to get the ABI

This commit is contained in:
Jonathan Rainville 2019-10-01 14:06:24 -04:00
parent cc307b74d5
commit bb52ce8de8
4 changed files with 15 additions and 253 deletions

View File

@ -18,6 +18,7 @@ then add embark-nim-compiler to the plugins section in `embark.json`:
"plugins": { "plugins": {
"embark-nim-compiler": { "embark-nim-compiler": {
"setupBlockchainOptions": true, "setupBlockchainOptions": true,
"useTestnet": false,
"libHeraPath": "path/to/libHera.so" "libHeraPath": "path/to/libHera.so"
} }
} }
@ -31,4 +32,10 @@ then add embark-nim-compiler to the plugins section in `embark.json`:
- [Embark](https://www.npmjs.com/package/embark) 5.0.0 or higher - [Embark](https://www.npmjs.com/package/embark) 5.0.0 or higher
- A valid eWasm ready node. See https://github.com/ewasm/testnet for more details - A valid eWasm ready node. See https://github.com/ewasm/testnet for more details
- Docker
### Troubleshooting
If you get an error related to docker or the image `jacqueswww/nimclang`, you might need to pull it first manually using:
```docker pull jacqueswww/nimclang```

View File

@ -11,6 +11,7 @@ class NimCompiler {
constructor(embark) { constructor(embark) {
this.events = embark.events; this.events = embark.events;
this.logger = embark.logger; this.logger = embark.logger;
this.dappPath = embark.dappPath;
embark.registerCompiler(".nim", this.compile.bind(this)); embark.registerCompiler(".nim", this.compile.bind(this));
@ -30,7 +31,7 @@ class NimCompiler {
genesisBlock: path.join(__dirname, './ewasm-testnet-geth-config.json'), genesisBlock: path.join(__dirname, './ewasm-testnet-geth-config.json'),
bootnodes: "enode://53458e6bf0353f3378e115034cf6c6039b9faed52548da9030b37b4672de4a8fd09f869c48d16f9f10937e7398ae0dbe8b9d271408da7a0cf47f42a09e662827@23.101.78.254:30303" bootnodes: "enode://53458e6bf0353f3378e115034cf6c6039b9faed52548da9030b37b4672de4a8fd09f869c48d16f9f10937e7398ae0dbe8b9d271408da7a0cf47f42a09e662827@23.101.78.254:30303"
}); });
cb(null, newConfig) cb(null, newConfig);
}); });
} }
} }
@ -54,15 +55,14 @@ class NimCompiler {
compiledObject[className].code = codeHex; compiledObject[className].code = codeHex;
// Get ABI from nim file // Get ABI from nim file
exec(`${path.join(__dirname, './tools/abi_gen')} ${file.path}`, (err, stdout, stderr) => { exec(`docker run --entrypoint="abi_gen" -v "${this.dappPath('contracts')}":/code/ -w /code/ jacqueswww/nimclang ${path.basename(file.path)}`, (err, stdout, stderr) => {
if (err) { if (err) {
this.logger.error('Error while getting ABI'); this.logger.error('Error while getting ABI');
this.logger.error(stderr); this.logger.error(stderr);
return eachCb(err); return eachCb(err);
} }
try { try {
const abi = JSON.parse(stdout); compiledObject[className].abiDefinition = JSON.parse(stdout);
compiledObject[className].abiDefinition = abi;
return eachCb(); return eachCb();
} catch (e) { } catch (e) {
return eachCb(e); return eachCb(e);
@ -74,5 +74,5 @@ class NimCompiler {
} }
} }
module.exports = NimCompiler module.exports = NimCompiler;

Binary file not shown.

View File

@ -1,245 +0,0 @@
import compiler / [ast, vmdef, vm, nimeval, options, parser, idents, condsyms,
nimconf, extccomp, astalgo, llstream, pathutils]
import json
import os
import
../nimplay/types
type
VariableType* = object
name: string
var_type: string
type
EventType* = object
name: string
var_type: string
indexed: bool
type
FunctionSignature* = object
name: string
inputs: seq[VariableType]
outputs: seq[VariableType]
constant: bool
payable: bool
type
EventSignature* = object
name: string
inputs: seq[EventType]
indexed: bool
proc get_abi_type(nimplay_type_str: string): string =
if nimplay_type_str in @["uint256", "bytes32", "int128", "uint128", "address"]:
nimplay_type_str
elif nimplay_type_str == "wei_value":
"uint128"
else:
raise newException(Exception, "Unknown type: " & nimplay_type_str)
proc string_to_ast*(s: string): PNode {.raises: [Exception] .} =
var conf = newConfigRef()
var cache = newIdentCache()
condsyms.initDefines(conf.symbols)
conf.projectName = "stdinfile"
conf.projectFull = "stdinfile".AbsoluteFile
conf.projectPath = canonicalizePath(conf, getCurrentDir().AbsoluteFile).AbsoluteDir
conf.projectIsStdin = true
loadConfigs(DefaultConfig, cache, conf)
extccomp.initVars(conf)
var node = parseString(s, cache, conf)
if len(node.sons) > 1:
result = node
else:
result = node.sons[0]
proc generate_function_signature(proc_def: PNode): FunctionSignature =
doAssert(proc_def.kind == nkFuncDef or proc_def.kind == nkProcDef)
var
func_sig = FunctionSignature()
for child in proc_def.sons:
case child.kind:
of nkPostfix:
func_sig.name = child[1].ident.s
of nkFormalParams:
for param in child:
case param.kind
of nkIdent:
func_sig.outputs.add(
VariableType(
name: "out1",
var_type: get_abi_type(param.ident.s)
)
)
of nkIdentDefs:
func_sig.inputs.add(
VariableType(
name: param.sons[0].ident.s,
var_type: get_abi_type(param.sons[1].ident.s)
)
)
of nkEmpty:
discard
else:
raise newException(Exception, "unknown param type")
of nkPragma:
for pragma_child in child:
if pragma_child.kind == nkIdent and pragma_child.ident.s == "payable":
func_sig.payable = true
else:
discard
return func_sig
proc generate_event_signature(proc_def: PNode): EventSignature =
doAssert(proc_def.kind == nkProcDef)
var
event_sig = EventSignature()
for child in proc_def.sons:
case child.kind:
of nkIdent:
event_sig.name = child.ident.s
of nkFormalParams:
for param in child:
if param.kind == nkIdentDefs:
var
ev: EventType
if param[0].kind == nkPragmaExpr and param[0][1].kind == nkPragma:
ev = EventType(
name: param.sons[0].sons[0].ident.s,
var_type: param.sons[1].ident.s,
indexed: true
)
else:
ev = EventType(
name: param.sons[0].ident.s,
var_type: param.sons[1].ident.s,
indexed: false
)
event_sig.inputs.add(ev)
else:
discard
event_sig # return
proc generateSignatures(stmts: PNode): (seq[FunctionSignature], seq[EventSignature]) =
var
public_functions: seq[FunctionSignature]
events: seq[EventSignature]
for child in stmts:
if child.kind == nkCall and len(child.sons) > 2:
var first_son = child.sons[0]
if first_son.kind == nkIdent and first_son.ident.s == "contract":
var main_block = child
for b in main_block.sons:
if b.kind == nkStmtList:
for s in b.sons:
if s.kind == nkVarSection: # handle getters.
for var_def in s.sons:
if var_def.kind == nkIdentDefs:
var
potential_postfix = var_def.sons[0]
if potential_postfix.kind == nkPostfix and potential_postfix.sons[0].ident.s == "*":
var
func_name = potential_postfix.sons[1].ident.s
type_name = var_def.sons[1].ident.s
sig = FunctionSignature(name: func_name)
sig.outputs.add(
VariableType(name: "out1", var_type: get_abi_type(type_name))
)
public_functions.add(
sig
)
elif s.kind == nkFuncDef or s.kind == nkProcDef:
# only get public functions.
if s[0].kind == nkPostfix and s[0][0].ident.s == "*":
public_functions.add(
generate_function_signature(s)
)
# handle event signature
elif s[6].kind == nkEmpty:
events.add(
generate_event_signature(s)
)
return (public_functions, events)
proc generateJSONABI(funcs: seq[FunctionSignature], events: seq[EventSignature]): string =
var jsonObject = %* []
proc getVarTypes(var_types: seq[VariableType]): JsonNode =
var types = %* []
for t in var_types:
types.add(%* {
"name": t.name,
"type": t.var_type,
})
types # return
func getFunc(f: FunctionSignature): JsonNode =
%* {
"name": f.name,
"inputs": getVarTypes(f.inputs),
"outputs": getVarTypes(f.outputs),
"constant": f.constant,
"payable": f.payable,
"type": "function"
}
proc getEventTypes(var_types: seq[EventType]): JsonNode =
var types = %* []
for t in var_types:
types.add(%* {
"name": t.name,
"type": t.var_type,
"indexed": t.indexed
})
types
func getEvent(e: EventSignature): JsonNode =
%* {
"inputs": getEventTypes(e.inputs),
"name": e.name,
"type": "event",
"anonymous": false
}
for fn in funcs:
jsonObject.add(getFunc(fn))
for event in events:
jsonObject.add(getEvent(event))
$jsonObject # return
proc main() =
if paramCount() != 1:
echo("Requires .nim file with contract() block macro")
quit()
if not existsFile(commandLineParams()[0]):
echo("Requires .nim file with contract() block macro")
quit()
var nimFile = commandLineParams()[0]
let node = string_to_ast(readFile(nimFile))
if node.kind == nkStmtList:
let (functions, events) = generateSignatures(node)
echo(generateJSONABI(functions, events))
else:
raise newException(Exception, "Expected nkStmtList")
when is_main_module:
main()