Skip to content

Commit a2bb683

Browse files
authored
Merge pull request #256 from ethereum/lowlevel-api
Expose the lowlevel compile API
2 parents 6b6adad + 3da93dc commit a2bb683

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,26 @@ There is also a direct method, `compileStandard`, which is only present on recen
105105

106106
Starting from version 0.4.20 a Semver compatible version number can be retrieved on every compiler release, including old ones, using the `semver()` method.
107107

108+
#### From version 0.5.0
109+
110+
Starting from version 0.5.0 the low-level functions are also exposed:
111+
- `solc.lowlevel.compileSingle`: the original entry point, supports only a single file
112+
- `solc.lowlevel.compileMulti`: this supports multiple files, introduced in 0.1.6
113+
- `solc.lowlevel.compileCallback`: this supports callbacks, introduced in 0.2.1
114+
- `solc.lowlevel.compileStandard`: this supports the Standard JSON input and output interface, introduced in 0.4.11
115+
116+
Example:
117+
```javascript
118+
var solc = require('solc')
119+
var input = {
120+
'lib.sol': 'library L { function f() returns (uint) { return 7; } }',
121+
'cont.sol': 'import "lib.sol"; contract x { function g() { L.f(); } }'
122+
}
123+
var output = JSON.parse(solc.lowlevel.compileMulti(JSON.stringify({ sources: input }), 1))
124+
for (var contractName in output.contracts)
125+
console.log(contractName + ': ' + output.contracts[contractName].bytecode)
126+
```
127+
108128
### Using with Electron
109129

110130
**Note:**

test/package.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ tape('Compilation', function (t) {
5555
st.ok(bytecode.length > 0);
5656
st.end();
5757
});
58+
59+
t.test('single files can be compiled (using lowlevel API)', function (st) {
60+
if (typeof solc.lowlevel.compileSingle !== 'function') {
61+
st.skip('Low-level compileSingle interface not implemented by this compiler version.');
62+
st.end();
63+
return;
64+
}
65+
var output = JSON.parse(solc.lowlevel.compileSingle('contract x { function g() public {} }'));
66+
st.ok('contracts' in output);
67+
var bytecode = getBytecode(output, '', 'x');
68+
st.ok(bytecode);
69+
st.ok(bytecode.length > 0);
70+
st.end();
71+
});
72+
5873
t.test('invalid source code fails properly', function (st) {
5974
var output = solc.compile('contract x { this is an invalid contract }');
6075
if (semver.lt(solc.semver(), '0.1.4')) {
@@ -103,6 +118,27 @@ tape('Compilation', function (t) {
103118
st.end();
104119
});
105120

121+
t.test('multiple files can be compiled (using lowlevel API)', function (st) {
122+
if (typeof solc.lowlevel.compileMulti !== 'function') {
123+
st.skip('Low-level compileMulti interface not implemented by this compiler version.');
124+
st.end();
125+
return;
126+
}
127+
128+
var input = {
129+
'lib.sol': 'library L { function f() public returns (uint) { return 7; } }',
130+
'cont.sol': 'import "lib.sol"; contract x { function g() public { L.f(); } }'
131+
};
132+
var output = JSON.parse(solc.lowlevel.compileMulti(JSON.stringify({sources: input})));
133+
var x = getBytecode(output, 'cont.sol', 'x');
134+
st.ok(x);
135+
st.ok(x.length > 0);
136+
var L = getBytecode(output, 'lib.sol', 'L');
137+
st.ok(L);
138+
st.ok(L.length > 0);
139+
st.end();
140+
});
141+
106142
t.test('lazy-loading callback works', function (st) {
107143
if (semver.lt(solc.semver(), '0.2.1')) {
108144
st.skip('Not supported by solc <0.2.1');
@@ -130,6 +166,33 @@ tape('Compilation', function (t) {
130166
st.end();
131167
});
132168

169+
t.test('lazy-loading callback works (using lowlevel API)', function (st) {
170+
if (typeof solc.lowlevel.compileCallback !== 'function') {
171+
st.skip('Low-level compileCallback interface not implemented by this compiler version.');
172+
st.end();
173+
return;
174+
}
175+
176+
var input = {
177+
'cont.sol': 'import "lib.sol"; contract x { function g() public { L.f(); } }'
178+
};
179+
function findImports (path) {
180+
if (path === 'lib.sol') {
181+
return { contents: 'library L { function f() public returns (uint) { return 7; } }' };
182+
} else {
183+
return { error: 'File not found' };
184+
}
185+
}
186+
var output = JSON.parse(solc.lowlevel.compileCallback(JSON.stringify({sources: input}), 0, findImports));
187+
var x = getBytecode(output, 'cont.sol', 'x');
188+
var L = getBytecode(output, 'lib.sol', 'L');
189+
st.ok(x);
190+
st.ok(x.length > 0);
191+
st.ok(L);
192+
st.ok(L.length > 0);
193+
st.end();
194+
});
195+
133196
t.test('lazy-loading callback works (with file not found)', function (st) {
134197
if (semver.lt(solc.semver(), '0.2.1')) {
135198
st.skip('Not supported by solc <0.2.1');
@@ -259,6 +322,7 @@ tape('Compilation', function (t) {
259322
st.ok(bytecodeExists(output, 'lib.sol', 'L'));
260323
st.end();
261324
});
325+
262326
t.test('invalid source code fails properly with standard JSON', function (st) {
263327
if (!solc.supportsStandard) {
264328
st.skip('Not supported by solc');
@@ -293,6 +357,7 @@ tape('Compilation', function (t) {
293357
}
294358
st.end();
295359
});
360+
296361
t.test('compiling standard JSON (with callback)', function (st) {
297362
if (!solc.supportsStandard) {
298363
st.skip('Not supported by solc');
@@ -337,6 +402,7 @@ tape('Compilation', function (t) {
337402
st.ok(bytecodeExists(output, 'lib.sol', 'L'));
338403
st.end();
339404
});
405+
340406
t.test('compiling standard JSON (using wrapper)', function (st) {
341407
// Example needs support for compileJSONMulti
342408
// FIXME: add test for wrapper without multiple files
@@ -418,6 +484,48 @@ tape('Compilation', function (t) {
418484
st.ok(L.length > 0);
419485
st.end();
420486
});
487+
488+
t.test('compiling standard JSON (using lowlevel API)', function (st) {
489+
if (typeof solc.lowlevel.compileStandard !== 'function') {
490+
st.skip('Low-level compileStandard interface not implemented by this compiler version.');
491+
st.end();
492+
return;
493+
}
494+
495+
var input = {
496+
'language': 'Solidity',
497+
'settings': {
498+
'libraries': {
499+
'lib.sol': {
500+
'L': '0x4200000000000000000000000000000000000001'
501+
}
502+
},
503+
'outputSelection': {
504+
'*': {
505+
'*': [ 'evm.bytecode' ]
506+
}
507+
}
508+
},
509+
'sources': {
510+
'lib.sol': {
511+
'content': 'library L { function f() public returns (uint) { return 7; } }'
512+
},
513+
'cont.sol': {
514+
'content': 'import "lib.sol"; contract x { function g() public { L.f(); } }'
515+
}
516+
}
517+
};
518+
519+
var output = JSON.parse(solc.lowlevel.compileStandard(JSON.stringify(input)));
520+
var x = getBytecodeStandard(output, 'cont.sol', 'x');
521+
st.ok(x);
522+
st.ok(x.length > 0);
523+
st.ok(Object.keys(linker.findLinkReferences(x)).length === 0);
524+
var L = getBytecodeStandard(output, 'lib.sol', 'L');
525+
st.ok(L);
526+
st.ok(L.length > 0);
527+
st.end();
528+
});
421529
});
422530

423531
tape('Loading Legacy Versions', function (t) {

wrapper.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ function setupMethods (soljson) {
223223
version: version,
224224
semver: versionToSemver,
225225
license: license,
226+
lowlevel: {
227+
compileSingle: compileJSON,
228+
compileMulti: compileJSONMulti,
229+
compileCallback: compileJSONCallback,
230+
compileStandard: compileStandard
231+
},
226232
compile: compile,
227233
compileStandard: compileStandard,
228234
compileStandardWrapper: compileStandardWrapper,

0 commit comments

Comments
 (0)