-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add support for option --allow-paths #1010
Changes from 7 commits
0510240
79f4159
52fa9ff
34caf03
8e6721b
5e1d607
76c6ac4
c924799
c8b8097
5b063b1
6f29521
351b0c2
c1294de
ccbadb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,15 +17,24 @@ | |
*/ | ||
package org.ethereum.solidity.compiler; | ||
|
||
import com.google.common.base.Joiner; | ||
import org.ethereum.config.SystemProperties; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.*; | ||
import java.io.BufferedOutputStream; | ||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.Serializable; | ||
import java.nio.file.Path; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
|
||
@Component | ||
public class SolidityCompiler { | ||
|
||
|
@@ -38,38 +47,96 @@ public SolidityCompiler(SystemProperties config) { | |
solc = new Solc(config); | ||
} | ||
|
||
public static Result compile(File sourceDirectory, boolean combinedJson, Options... options) throws IOException { | ||
public static Result compile(File sourceDirectory, boolean combinedJson, Option... options) throws IOException { | ||
return getInstance().compileSrc(sourceDirectory, false, combinedJson, options); | ||
} | ||
|
||
public enum Options { | ||
public static final class Options { | ||
public static final OutputOption AST = OutputOption.AST; | ||
public static final OutputOption BIN = OutputOption.BIN; | ||
public static final OutputOption INTERFACE = OutputOption.INTERFACE; | ||
public static final OutputOption ABI = OutputOption.ABI; | ||
public static final OutputOption METADATA = OutputOption.METADATA; | ||
public static final OutputOption ASTJSON = OutputOption.ASTJSON; | ||
} | ||
|
||
public interface Option extends Serializable { | ||
String getValue(); | ||
String getName(); | ||
} | ||
|
||
public static class ListOption implements Option { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code currently designed only for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are absolutely right; I'll do the necessary changes. |
||
private String name; | ||
private List values; | ||
|
||
public ListOption(String name, List values) { | ||
this.name = name; | ||
this.values = values; | ||
} | ||
|
||
@Override public String getValue() { | ||
StringBuilder result = new StringBuilder(); | ||
for (Object value : values) { | ||
if (OutputOption.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((OutputOption) value).getName() : ',' + ((OutputOption) value).getName()); | ||
} else if (Path.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((Path) value).toAbsolutePath().toString() : ',' + ((Path) value).toAbsolutePath().toString()); | ||
} else if (File.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((File) value).getAbsolutePath() : ',' + ((File) value).getAbsolutePath()); | ||
} else if (String.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? value : "," + value); | ||
} else { | ||
throw new UnsupportedOperationException("Unexpected type, value '" + value + "' cannot be retrieved."); | ||
} | ||
} | ||
return result.toString(); | ||
} | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { return name; } | ||
} | ||
|
||
private enum NameOnlyOption implements Option { | ||
OPTIMIZE("optimize"), | ||
VERSION("version"); | ||
|
||
private String name; | ||
|
||
NameOnlyOption(String name) { | ||
this.name = name; | ||
} | ||
|
||
@Override public String getValue() { return ""; } | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { | ||
return name; | ||
} | ||
} | ||
|
||
private enum OutputOption implements Option { | ||
AST("ast"), | ||
BIN("bin"), | ||
INTERFACE("interface"), | ||
ABI("abi"), | ||
METADATA("metadata"), | ||
METADATA("metadata"), | ||
ASTJSON("ast-json"); | ||
|
||
private String name; | ||
|
||
Options(String name) { | ||
OutputOption(String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
@Override public String getValue() { return ""; } | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { | ||
return name; | ||
} | ||
} | ||
|
||
public static class Result { | ||
public String errors; | ||
public String output; | ||
private boolean success = false; | ||
private boolean success; | ||
|
||
public Result(String errors, String output, boolean success) { | ||
this.errors = errors; | ||
|
@@ -125,11 +192,11 @@ public void run() { | |
} | ||
} | ||
|
||
public static Result compile(byte[] source, boolean combinedJson, Options... options) throws IOException { | ||
public static Result compile(byte[] source, boolean combinedJson, Option... options) throws IOException { | ||
return getInstance().compileSrc(source, false, combinedJson, options); | ||
} | ||
|
||
public Result compileSrc(File source, boolean optimize, boolean combinedJson, Options... options) throws IOException { | ||
public Result compileSrc(File source, boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = prepareCommandOptions(optimize, combinedJson, options); | ||
|
||
commandParts.add(source.getAbsolutePath()); | ||
|
@@ -156,24 +223,33 @@ public Result compileSrc(File source, boolean optimize, boolean combinedJson, Op | |
return new Result(error.getContent(), output.getContent(), success); | ||
} | ||
|
||
private List<String> prepareCommandOptions(boolean optimize, boolean combinedJson, Options[] options) throws IOException { | ||
private List<String> prepareCommandOptions(boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = new ArrayList<>(); | ||
commandParts.add(solc.getExecutable().getCanonicalPath()); | ||
if (optimize) { | ||
commandParts.add("--optimize"); | ||
commandParts.add("--" + NameOnlyOption.OPTIMIZE.getName()); | ||
} | ||
if (combinedJson) { | ||
commandParts.add("--combined-json"); | ||
commandParts.add(Joiner.on(',').join(options)); | ||
ListOption combinedJsonOption = new ListOption("combined-json", getElementsOf(OutputOption.class, options)); | ||
commandParts.add("--" + combinedJsonOption.getName()); | ||
commandParts.add(combinedJsonOption.getValue()); | ||
} else { | ||
for (Options option : options) { | ||
for (Option option : getElementsOf(OutputOption.class, options)) { | ||
commandParts.add("--" + option.getName()); | ||
} | ||
} | ||
for (Option option : getElementsOf(ListOption.class, options)) { | ||
commandParts.add("--" + option.getName()); | ||
commandParts.add(option.getValue()); | ||
} | ||
return commandParts; | ||
} | ||
|
||
public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, Options... options) throws IOException { | ||
private static <T> List<T> getElementsOf(Class<T> clazz, Option... options) { | ||
return Arrays.stream(options).filter(clazz::isInstance).map(clazz::cast).collect(toList()); | ||
} | ||
|
||
public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = prepareCommandOptions(optimize, combinedJson, options); | ||
|
||
ProcessBuilder processBuilder = new ProcessBuilder(commandParts) | ||
|
@@ -205,7 +281,7 @@ public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, | |
public static String runGetVersionOutput() throws IOException { | ||
List<String> commandParts = new ArrayList<>(); | ||
commandParts.add(getInstance().solc.getExecutable().getCanonicalPath()); | ||
commandParts.add("--version"); | ||
commandParts.add("--" + NameOnlyOption.VERSION.getName()); | ||
|
||
ProcessBuilder processBuilder = new ProcessBuilder(commandParts) | ||
.directory(getInstance().solc.getExecutable().getParentFile()); | ||
|
@@ -231,12 +307,10 @@ public static String runGetVersionOutput() throws IOException { | |
throw new RuntimeException("Problem getting solc version: " + error.getContent()); | ||
} | ||
|
||
|
||
|
||
public static SolidityCompiler getInstance() { | ||
if (INSTANCE == null) { | ||
INSTANCE = new SolidityCompiler(SystemProperties.getDefault()); | ||
} | ||
return INSTANCE; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -372,15 +372,15 @@ public void createContractFork() throws Exception { | |
"}"; | ||
|
||
StandaloneBlockchain bc = new StandaloneBlockchain(); | ||
SolidityContract parent = bc.submitNewContract(contractSrc, "Parent"); | ||
SolidityContract parent = bc.submitNewContract(contractSrc, "<stdin>:Parent"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's a bad thing with all this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, I didn't spent a lot of thoughts on this, simply adjusted the tests to work with the new Solidity compiler version. To me it seems that the creators of Solidity, with version 0.4.9, added some form of a poor men's namespace support; that is, requiring to prefix each contract with I don't see how the new contract's namespace information could be ignored in the production code. Thoughts/concerns? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, what I suggest:
What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand your suggestion, but I believe that would not be as designed by the creators of Solidity. To me it seems, since Solidity version We need to agree on this first before we can think about how to better address this change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Look, now contract name just contains more information: path (or There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I've called @mkalinin for his opinion, he will reply later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I noticed, our messages somehow overlapped. I can relate to the discontent towards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more thing, doing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both of you have thoughts meaningful to me. I agree with @zilm13 that contract name is just a name and it's incorrect to prefix it with contract source, cause that will definitely confuse the user. On the other hand @tglaeser is right pointing that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the input. I'll go forward and make the necessary changes and update the pull request... |
||
Block b1 = bc.createBlock(); | ||
Block b2 = bc.createBlock(); | ||
parent.callFunction("createChild", 100); | ||
Block b3 = bc.createBlock(); | ||
byte[] childAddress = (byte[]) parent.callConstFunction("child")[0]; | ||
parent.callFunction("createChild", 200); | ||
Block b2_ = bc.createForkBlock(b1); | ||
SolidityContract child = bc.createExistingContractFromSrc(contractSrc, "Child", childAddress); | ||
SolidityContract child = bc.createExistingContractFromSrc(contractSrc, "<stdin>:Child", childAddress); | ||
child.callFunction("sum"); | ||
Block b4 = bc.createBlock(); | ||
Assert.assertEquals(BigInteger.valueOf(100 + 333 + 100 + 444), child.callConstFunction("c")[0]); | ||
|
@@ -407,9 +407,9 @@ public void createContractFork1() throws Exception { | |
StandaloneBlockchain bc = new StandaloneBlockchain(); | ||
Block b1 = bc.createBlock(); | ||
Block b2 = bc.createBlock(); | ||
SolidityContract a = bc.submitNewContract(contractSrc, "A"); | ||
SolidityContract a = bc.submitNewContract(contractSrc, "<stdin>:A"); | ||
Block b3 = bc.createBlock(); | ||
SolidityContract b = bc.submitNewContract(contractSrc, "B"); | ||
SolidityContract b = bc.submitNewContract(contractSrc, "<stdin>:B"); | ||
Block b2_ = bc.createForkBlock(b1); | ||
Assert.assertEquals(BigInteger.valueOf(333), a.callConstFunction("a")[0]); | ||
Assert.assertEquals(BigInteger.valueOf(111), b.callConstFunction(b2_, "a")[0]); | ||
|
@@ -441,11 +441,11 @@ public void createValueTest() throws IOException, InterruptedException { | |
" }\n" + | ||
"}"; | ||
StandaloneBlockchain bc = new StandaloneBlockchain().withAutoblock(true); | ||
SolidityContract a = bc.submitNewContract(contract, "A"); | ||
SolidityContract a = bc.submitNewContract(contract, "<stdin>:A"); | ||
bc.sendEther(a.getAddress(), BigInteger.valueOf(10_000)); | ||
a.callFunction(10, "create"); | ||
byte[] childAddress = (byte[]) a.callConstFunction("child")[0]; | ||
SolidityContract b = bc.createExistingContractFromSrc(contract, "B", childAddress); | ||
SolidityContract b = bc.createExistingContractFromSrc(contract, "<stdin>:B", childAddress); | ||
BigInteger val = (BigInteger) b.callConstFunction("valReceived")[0]; | ||
Assert.assertEquals(20, val.longValue()); | ||
} | ||
|
@@ -502,7 +502,7 @@ public void operateNotExistingContractTest() throws IOException, InterruptedExce | |
StandaloneBlockchain bc = new StandaloneBlockchain() | ||
.withGasPrice(1) | ||
.withGasLimit(5_000_000L); | ||
SolidityContract a = bc.submitNewContract(contractA, "A"); | ||
SolidityContract a = bc.submitNewContract(contractA, "<stdin>:A"); | ||
bc.createBlock(); | ||
|
||
{ | ||
|
@@ -514,7 +514,7 @@ public void operateNotExistingContractTest() throws IOException, InterruptedExce | |
|
||
// checking balance of not existed address should take | ||
// less that gas limit | ||
Assert.assertEquals(21508, spent); | ||
Assert.assertEquals(21532, spent); | ||
} | ||
|
||
{ | ||
|
@@ -558,7 +558,7 @@ public void deepRecursionTest() throws Exception { | |
"}"; | ||
|
||
StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); | ||
SolidityContract a = bc.submitNewContract(contractA, "A"); | ||
SolidityContract a = bc.submitNewContract(contractA, "<stdin>:A"); | ||
bc.createBlock(); | ||
a.callFunction("recursive"); | ||
bc.createBlock(); | ||
|
@@ -647,7 +647,7 @@ public void selfdestructAttack() throws Exception { | |
StandaloneBlockchain bc = new StandaloneBlockchain() | ||
.withGasLimit(1_000_000_000L) | ||
.withDbDelay(0); | ||
SolidityContract a = bc.submitNewContract(contractSrc, "A"); | ||
SolidityContract a = bc.submitNewContract(contractSrc, "<stdin>:A"); | ||
bc.createBlock(); | ||
a.callFunction("f"); | ||
bc.createBlock(); | ||
|
@@ -770,7 +770,7 @@ public void suicideInFailedCall() throws Exception { | |
"}"; | ||
|
||
StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); | ||
SolidityContract a = bc.submitNewContract(contractA, "A"); | ||
SolidityContract a = bc.submitNewContract(contractA, "<stdin>:A"); | ||
bc.createBlock(); | ||
final BigInteger[] refund = new BigInteger[1]; | ||
bc.addEthereumListener(new EthereumListenerAdapter() { | ||
|
@@ -803,7 +803,7 @@ public void logInFailedCall() throws Exception { | |
"}"; | ||
|
||
StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); | ||
SolidityContract a = bc.submitNewContract(contractA, "A"); | ||
SolidityContract a = bc.submitNewContract(contractA, "<stdin>:A"); | ||
bc.createBlock(); | ||
final List<LogInfo> logs = new ArrayList<>(); | ||
bc.addEthereumListener(new EthereumListenerAdapter() { | ||
|
@@ -831,14 +831,14 @@ public void ecRecoverTest() throws Exception { | |
" mstore(0x120, v)" + | ||
" mstore(0x140, r)" + | ||
" mstore(0x160, s)" + | ||
" callcode(0x50000, 0x01, 0x0, 0x100, 0x80, 0x200, 0x220)" + // call ecrecover | ||
" let ret := callcode(0x50000, 0x01, 0x0, 0x100, 0x80, 0x200, 0x220)" + // call ecrecover | ||
" return(0x200, 0x20)" + | ||
" }" + | ||
" }" + | ||
"}"; | ||
|
||
StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); | ||
SolidityContract a = bc.submitNewContract(contractA, "A"); | ||
SolidityContract a = bc.submitNewContract(contractA, "<stdin>:A"); | ||
bc.createBlock(); | ||
|
||
ECKey key = ECKey.fromPrivate(BigInteger.ONE); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you, please, add comment here, that it's here for backward compatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.