From 051024060ad237b2f5271dc3a3e7ec56b9f47d47 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Wed, 14 Feb 2018 10:19:47 -0500 Subject: [PATCH 01/13] Replacing the enum type 'Options' with more flexible interface 'Option' --- .../ethereum/solidity/compiler/Option.java | 6 + .../solidity/compiler/SolidityCompiler.java | 108 +++++++++++++----- 2 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java new file mode 100644 index 0000000000..037dfee43b --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java @@ -0,0 +1,6 @@ +package org.ethereum.solidity.compiler; + +public interface Option { + String getValue(); + String getName(); +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java index 6b67723279..b30d98d22a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java @@ -17,14 +17,20 @@ */ 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.util.ArrayList; +import java.util.Arrays; import java.util.List; +import static java.util.stream.Collectors.toList; @Component public class SolidityCompiler { @@ -38,30 +44,75 @@ 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; + } + + private static class ListOption implements Option { + private String name; + private List values; + + 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()); + } + } + 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; } } @@ -69,7 +120,7 @@ public String toString() { 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 +176,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 commandParts = prepareCommandOptions(optimize, combinedJson, options); commandParts.add(source.getAbsolutePath()); @@ -156,24 +207,31 @@ public Result compileSrc(File source, boolean optimize, boolean combinedJson, Op return new Result(error.getContent(), output.getContent(), success); } - private List prepareCommandOptions(boolean optimize, boolean combinedJson, Options[] options) throws IOException { + private List prepareCommandOptions(boolean optimize, boolean combinedJson, Option... options) throws IOException { List 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) { - commandParts.add("--" + option.getName()); + for (Option option : getElementsOf(OutputOption.class, options)) { + if (option.getClass().isEnum()) { + commandParts.add("--" + option.getName()); + } } } return commandParts; } - public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, Options... options) throws IOException { + private static List getElementsOf(Class 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 commandParts = prepareCommandOptions(optimize, combinedJson, options); ProcessBuilder processBuilder = new ProcessBuilder(commandParts) @@ -205,7 +263,7 @@ public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, public static String runGetVersionOutput() throws IOException { List 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 +289,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; } -} +} \ No newline at end of file From 79f4159f099e404e287819943124c7f7a96c9640 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Wed, 14 Feb 2018 13:22:37 -0500 Subject: [PATCH 02/13] Upgrading module org.ethereum:solcJ-all to version 0.4.10 --- ethereumj-core/build.gradle | 2 +- .../org/ethereum/core/ImportLightTest.java | 26 +++++++++---------- .../org/ethereum/core/TransactionTest.java | 8 +++--- .../org/ethereum/solidity/CompilerTest.java | 8 +++--- .../util/StandaloneBlockchainTest.java | 6 ++--- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ethereumj-core/build.gradle b/ethereumj-core/build.gradle index f2d0886d4b..9d173bf8c6 100644 --- a/ethereumj-core/build.gradle +++ b/ethereumj-core/build.gradle @@ -121,7 +121,7 @@ dependencies { compile "org.ethereum:leveldbjni-all:1.18.3" // native leveldb components - compile "org.ethereum:solcJ-all:0.4.8" // Solidity Compiler win/mac/linux binaries + compile "org.ethereum:solcJ-all:0.4.10" // Solidity Compiler win/mac/linux binaries compile "com.cedarsoftware:java-util:1.8.0" // for deep equals compile "org.javassist:javassist:3.15.0-GA" diff --git a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java index e9dba75d36..800a2491e7 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -372,7 +372,7 @@ public void createContractFork() throws Exception { "}"; StandaloneBlockchain bc = new StandaloneBlockchain(); - SolidityContract parent = bc.submitNewContract(contractSrc, "Parent"); + SolidityContract parent = bc.submitNewContract(contractSrc, ":Parent"); Block b1 = bc.createBlock(); Block b2 = bc.createBlock(); parent.callFunction("createChild", 100); @@ -380,7 +380,7 @@ public void createContractFork() throws Exception { 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, ":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, ":A"); Block b3 = bc.createBlock(); - SolidityContract b = bc.submitNewContract(contractSrc, "B"); + SolidityContract b = bc.submitNewContract(contractSrc, ":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, ":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, ":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, ":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(21512, 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, ":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, ":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, ":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, ":A"); bc.createBlock(); final List logs = new ArrayList<>(); bc.addEthereumListener(new EthereumListenerAdapter() { @@ -838,7 +838,7 @@ public void ecRecoverTest() throws Exception { "}"; StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); - SolidityContract a = bc.submitNewContract(contractA, "A"); + SolidityContract a = bc.submitNewContract(contractA, ":A"); bc.createBlock(); ECKey key = ECKey.fromPrivate(BigInteger.ONE); diff --git a/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java b/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java index 79b89ebd28..d3110bc607 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java @@ -576,14 +576,14 @@ public void multiSuicideTest() throws IOException, InterruptedException { ECKey sender = ECKey.fromPrivate(Hex.decode("3ec771c31cac8c0dba77a69e503765701d3c2bb62435888d4ffa38fed60c445c")).compress(); System.out.println("address: " + Hex.toHexString(sender.getAddress())); - if (cres.contracts.get("PsychoKiller") != null) { + if (cres.contracts.get(":PsychoKiller") != null) { Transaction tx = createTx(blockchain, sender, new byte[0], - Hex.decode(cres.contracts.get("PsychoKiller").bin)); + Hex.decode(cres.contracts.get(":PsychoKiller").bin)); executeTransaction(blockchain, tx); byte[] contractAddress = tx.getContractAddress(); - CallTransaction.Contract contract1 = new CallTransaction.Contract(cres.contracts.get("PsychoKiller").abi); + CallTransaction.Contract contract1 = new CallTransaction.Contract(cres.contracts.get(":PsychoKiller").abi); byte[] callData = contract1.getByName("multipleHomocide").encode(); Transaction tx1 = createTx(blockchain, sender, contractAddress, callData, 0l); @@ -662,7 +662,7 @@ public void receiptErrorTest() throws Exception { contract.getBytes(), true, SolidityCompiler.Options.ABI, SolidityCompiler.Options.BIN); System.out.println(res.errors); CompilationResult cres = CompilationResult.parse(res.output); - Transaction tx = createTx(blockchain, sender, new byte[0], Hex.decode(cres.contracts.get("GasConsumer").bin), 0); + Transaction tx = createTx(blockchain, sender, new byte[0], Hex.decode(cres.contracts.get(":GasConsumer").bin), 0); TransactionReceipt receipt = executeTransaction(blockchain, tx).getReceipt(); receipt = new TransactionReceipt(receipt.getEncoded()); diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index 475c4843a6..5cb38b9cdc 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -66,8 +66,8 @@ public void simpleTest() throws IOException { System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - if (result.contracts.get("a") != null) - System.out.println(result.contracts.get("a").bin); + if (result.contracts.get(":a") != null) + System.out.println(result.contracts.get(":a").bin); else Assert.fail(); } @@ -86,7 +86,7 @@ public void defaultFuncTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get("a"); + CompilationResult.ContractMetadata a = result.contracts.get(":a"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.printf(contract.functions[0].toString()); } @@ -102,7 +102,7 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get("test1"); + CompilationResult.ContractMetadata a = result.contracts.get(source.getAbsolutePath() + ":test1"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.printf(contract.functions[0].toString()); } diff --git a/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java b/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java index 3132a9c6d7..a78f6d6bf6 100644 --- a/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java @@ -50,7 +50,7 @@ public void constructorTest() { " uint public b;" + " function A(uint a_, uint b_) {a = a_; b = b_; }" + "}", - "A", 555, 777 + ":A", 555, 777 ); Assert.assertEquals(BigInteger.valueOf(555), a.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(777), a.callConstFunction("b")[0]); @@ -61,7 +61,7 @@ public void constructorTest() { " uint public b;" + " function A(string a_, uint b_) {a = a_; b = b_; }" + "}", - "A", "This string is longer than 32 bytes...", 777 + ":A", "This string is longer than 32 bytes...", 777 ); Assert.assertEquals("This string is longer than 32 bytes...", b.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(777), b.callConstFunction("b")[0]); @@ -98,7 +98,7 @@ public void fixedSizeArrayTest() { " address public c;" + " address public d;" + " function A(uint[2] arr, address a1, address a2) {a = arr[0]; b = arr[1]; c = a1; d = a2;}" + - "}", "A", + "}", ":A", new Integer[]{111, 222}, addr1.getAddress(), addr2.getAddress()); Assert.assertEquals(BigInteger.valueOf(111), a.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(222), a.callConstFunction("b")[0]); From 52fa9ffe994ed97063ee9431228a3b63e7723138 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Wed, 14 Feb 2018 15:47:29 -0500 Subject: [PATCH 03/13] Preparing for upgrade of module org.ethereum:solcJ-all to version 0.4.19 ... adding new function property stateMutability (not yet used) --- .../src/main/java/org/ethereum/core/CallTransaction.java | 8 ++++++++ .../src/test/java/org/ethereum/core/ImportLightTest.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/core/CallTransaction.java b/ethereumj-core/src/main/java/org/ethereum/core/CallTransaction.java index 6375f31a17..260efb8e1b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/CallTransaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/CallTransaction.java @@ -86,6 +86,13 @@ public String getType() { } } + public enum StateMutabilityType { + pure, + view, + nonpayable, + payable + } + public enum FunctionType { constructor, function, @@ -101,6 +108,7 @@ public static class Function { public Param[] inputs = new Param[0]; public Param[] outputs = new Param[0]; public FunctionType type; + public StateMutabilityType stateMutability; private Function() {} diff --git a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java index 800a2491e7..2501db893f 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -514,7 +514,7 @@ public void operateNotExistingContractTest() throws IOException, InterruptedExce // checking balance of not existed address should take // less that gas limit - Assert.assertEquals(21512, spent); + Assert.assertEquals(21532, spent); } { @@ -831,7 +831,7 @@ 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)" + " }" + " }" + From 34caf0385c8f589b95a59d89f72e4cc2344b6f51 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Wed, 14 Feb 2018 17:11:07 -0500 Subject: [PATCH 04/13] Adding support for option --allow-paths --- .../solidity/compiler/SolidityCompiler.java | 22 ++++-- .../org/ethereum/solidity/CompilerTest.java | 73 +++++++++++++++++-- .../src/test/resources/solidity/file2.sol | 4 +- .../src/test/resources/solidity/foo/file3.sol | 6 ++ 4 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 ethereumj-core/src/test/resources/solidity/foo/file3.sol diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java index b30d98d22a..55e1304507 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java @@ -27,9 +27,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +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 @@ -57,11 +59,11 @@ public static final class Options { public static final OutputOption ASTJSON = OutputOption.ASTJSON; } - private static class ListOption implements Option { + public static class ListOption implements Option { private String name; private List values; - ListOption(String name, List values) { + public ListOption(String name, List values) { this.name = name; this.values = values; } @@ -71,6 +73,14 @@ private static class ListOption implements Option { 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(); @@ -219,11 +229,13 @@ private List prepareCommandOptions(boolean optimize, boolean combinedJso commandParts.add(combinedJsonOption.getValue()); } else { for (Option option : getElementsOf(OutputOption.class, options)) { - if (option.getClass().isEnum()) { - commandParts.add("--" + option.getName()); - } + commandParts.add("--" + option.getName()); } } + for (Option option : getElementsOf(ListOption.class, options)) { + commandParts.add("--" + option.getName()); + commandParts.add(option.getValue()); + } return commandParts; } diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index 5cb38b9cdc..725873366f 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -23,8 +23,10 @@ import org.junit.Assert; import org.junit.Test; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; import static org.ethereum.solidity.compiler.SolidityCompiler.Options.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -88,25 +90,82 @@ public void defaultFuncTest() throws IOException { CompilationResult.ContractMetadata a = result.contracts.get(":a"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); - System.out.printf(contract.functions[0].toString()); + System.out.print(contract.functions[0].toString()); } @Test public void compileFilesTest() throws IOException { - File source = new File("src/test/resources/solidity/file1.sol"); + Path source = Paths.get("src","test","resources","solidity","file1.sol"); - SolidityCompiler.Result res = SolidityCompiler.compile( - source, true, ABI, BIN, INTERFACE, METADATA); + SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA); + System.out.println("Out: '" + res.output + "'"); + System.out.println("Err: '" + res.errors + "'"); + CompilationResult result = CompilationResult.parse(res.output); + + CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test1"); + CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); + System.out.print(contract.functions[0].toString()); + } + + @Test public void compileFilesWithImportTest() throws IOException { + + Path source = Paths.get("src","test","resources","solidity","file2.sol"); + + SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA); + System.out.println("Out: '" + res.output + "'"); + System.out.println("Err: '" + res.errors + "'"); + CompilationResult result = CompilationResult.parse(res.output); + + CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test2"); + CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); + System.out.print(contract.functions[0].toString()); + } + + @Test public void compileFilesWithImportFromParentFileTest() throws IOException { + + Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); + + SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent().toFile())); + SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); + System.out.println("Out: '" + res.output + "'"); + System.out.println("Err: '" + res.errors + "'"); + CompilationResult result = CompilationResult.parse(res.output); + + CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); + CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); + System.out.print(contract.functions[0].toString()); + } + + @Test public void compileFilesWithImportFromParentStringTest() throws IOException { + + Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); + + SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent().toAbsolutePath().toString())); + SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.getAbsolutePath() + ":test1"); + CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); - System.out.printf(contract.functions[0].toString()); + System.out.print(contract.functions[0].toString()); } + @Test public void compileFilesWithImportFromParentPathTest() throws IOException { + + Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); + + SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent())); + SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); + System.out.println("Out: '" + res.output + "'"); + System.out.println("Err: '" + res.errors + "'"); + CompilationResult result = CompilationResult.parse(res.output); + + CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); + CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); + System.out.print(contract.functions[0].toString()); + } public static void main(String[] args) throws Exception { new CompilerTest().simpleTest(); diff --git a/ethereumj-core/src/test/resources/solidity/file2.sol b/ethereumj-core/src/test/resources/solidity/file2.sol index 8d038be125..30c992be3a 100644 --- a/ethereumj-core/src/test/resources/solidity/file2.sol +++ b/ethereumj-core/src/test/resources/solidity/file2.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.7; -import "file1.sol"; +import "./file1.sol"; -contract test2{ +contract test2 is test1 { } diff --git a/ethereumj-core/src/test/resources/solidity/foo/file3.sol b/ethereumj-core/src/test/resources/solidity/foo/file3.sol new file mode 100644 index 0000000000..ffde182d57 --- /dev/null +++ b/ethereumj-core/src/test/resources/solidity/foo/file3.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.4.7; + +import "../file1.sol"; + +contract test3 is test1 { +} From 8e6721b268fa9d312a9f601b11453ee028a9112f Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Thu, 15 Feb 2018 13:11:03 -0500 Subject: [PATCH 05/13] Upgrading module org.ethereum:solcJ-all to version 0.4.19 --- ethereumj-core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereumj-core/build.gradle b/ethereumj-core/build.gradle index 9d173bf8c6..854658be38 100644 --- a/ethereumj-core/build.gradle +++ b/ethereumj-core/build.gradle @@ -121,7 +121,7 @@ dependencies { compile "org.ethereum:leveldbjni-all:1.18.3" // native leveldb components - compile "org.ethereum:solcJ-all:0.4.10" // Solidity Compiler win/mac/linux binaries + compile "org.ethereum:solcJ-all:0.4.19" // Solidity Compiler win/mac/linux binaries compile "com.cedarsoftware:java-util:1.8.0" // for deep equals compile "org.javassist:javassist:3.15.0-GA" From 5e1d6078a8902614ec5c890f4c37cff13c3fef7e Mon Sep 17 00:00:00 2001 From: "U-EUR\\tglaeser" Date: Thu, 15 Feb 2018 15:15:34 -0500 Subject: [PATCH 06/13] Making Option and inner interface --- .../main/java/org/ethereum/solidity/compiler/Option.java | 6 ------ .../org/ethereum/solidity/compiler/SolidityCompiler.java | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java deleted file mode 100644 index 037dfee43b..0000000000 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/Option.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.ethereum.solidity.compiler; - -public interface Option { - String getValue(); - String getName(); -} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java index 55e1304507..f299b0dfe8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java @@ -59,6 +59,11 @@ public static final class Options { public static final OutputOption ASTJSON = OutputOption.ASTJSON; } + public interface Option { + String getValue(); + String getName(); + } + public static class ListOption implements Option { private String name; private List values; From 76c6ac416c090259982f264f92e076d2c78a94af Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Thu, 15 Feb 2018 16:10:56 -0500 Subject: [PATCH 07/13] Make objects of type Option serializable --- .../java/org/ethereum/solidity/compiler/SolidityCompiler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java index f299b0dfe8..18194bf17a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java @@ -27,6 +27,7 @@ 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; @@ -59,7 +60,7 @@ public static final class Options { public static final OutputOption ASTJSON = OutputOption.ASTJSON; } - public interface Option { + public interface Option extends Serializable { String getValue(); String getName(); } From c8b8097e8d5dd2bcd464f224a15c49b48a4d8233 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Tue, 27 Feb 2018 14:21:26 -0500 Subject: [PATCH 08/13] Adding new option types CombinedJson and AllowPaths ... registering all supported options under SolidityCompiler.Options --- .../solidity/compiler/SolidityCompiler.java | 28 +++++++++++++++---- .../org/ethereum/solidity/CompilerTest.java | 6 ++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java index 18194bf17a..303a97ace6 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/SolidityCompiler.java @@ -51,6 +51,10 @@ public static Result compile(File sourceDirectory, boolean combinedJson, Option. return getInstance().compileSrc(sourceDirectory, false, combinedJson, options); } + /** + * This class is mainly here for backwards compatibility; however we are now reusing it making it the solely public + * interface listing all the supported options. + */ public static final class Options { public static final OutputOption AST = OutputOption.AST; public static final OutputOption BIN = OutputOption.BIN; @@ -58,6 +62,20 @@ public static final class Options { public static final OutputOption ABI = OutputOption.ABI; public static final OutputOption METADATA = OutputOption.METADATA; public static final OutputOption ASTJSON = OutputOption.ASTJSON; + + private static final NameOnlyOption OPTIMIZE = NameOnlyOption.OPTIMIZE; + private static final NameOnlyOption VERSION = NameOnlyOption.VERSION; + + private static class CombinedJson extends ListOption { + private CombinedJson(List values) { + super("combined-json", values); + } + } + public static class AllowPaths extends ListOption { + public AllowPaths(List values) { + super("allow-paths", values); + } + } } public interface Option extends Serializable { @@ -65,11 +83,11 @@ public interface Option extends Serializable { String getName(); } - public static class ListOption implements Option { + private static class ListOption implements Option { private String name; private List values; - public ListOption(String name, List values) { + private ListOption(String name, List values) { this.name = name; this.values = values; } @@ -227,10 +245,10 @@ private List prepareCommandOptions(boolean optimize, boolean combinedJso List commandParts = new ArrayList<>(); commandParts.add(solc.getExecutable().getCanonicalPath()); if (optimize) { - commandParts.add("--" + NameOnlyOption.OPTIMIZE.getName()); + commandParts.add("--" + Options.OPTIMIZE.getName()); } if (combinedJson) { - ListOption combinedJsonOption = new ListOption("combined-json", getElementsOf(OutputOption.class, options)); + Option combinedJsonOption = new Options.CombinedJson(getElementsOf(OutputOption.class, options)); commandParts.add("--" + combinedJsonOption.getName()); commandParts.add(combinedJsonOption.getValue()); } else { @@ -281,7 +299,7 @@ public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, public static String runGetVersionOutput() throws IOException { List commandParts = new ArrayList<>(); commandParts.add(getInstance().solc.getExecutable().getCanonicalPath()); - commandParts.add("--" + NameOnlyOption.VERSION.getName()); + commandParts.add("--" + Options.VERSION.getName()); ProcessBuilder processBuilder = new ProcessBuilder(commandParts) .directory(getInstance().solc.getExecutable().getParentFile()); diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index 725873366f..f65d9fe6f4 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -126,7 +126,7 @@ public void compileFilesTest() throws IOException { Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); - SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent().toFile())); + SolidityCompiler.Option allowPathsOption = new SolidityCompiler.Options.AllowPaths(Collections.singletonList(source.getParent().getParent().toFile())); SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); @@ -141,7 +141,7 @@ public void compileFilesTest() throws IOException { Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); - SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent().toAbsolutePath().toString())); + SolidityCompiler.Option allowPathsOption = new SolidityCompiler.Options.AllowPaths(Collections.singletonList(source.getParent().getParent().toAbsolutePath().toString())); SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); @@ -156,7 +156,7 @@ public void compileFilesTest() throws IOException { Path source = Paths.get("src","test","resources","solidity","foo","file3.sol"); - SolidityCompiler.ListOption allowPathsOption = new SolidityCompiler.ListOption("allow-paths", Collections.singletonList(source.getParent().getParent())); + SolidityCompiler.Option allowPathsOption = new SolidityCompiler.Options.AllowPaths(Collections.singletonList(source.getParent().getParent())); SolidityCompiler.Result res = SolidityCompiler.compile(source.toFile(), true, ABI, BIN, INTERFACE, METADATA, allowPathsOption); System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); From 5b063b15fae686c925936a949d3153f44548157f Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Fri, 2 Mar 2018 13:50:33 -0500 Subject: [PATCH 09/13] Reverting the fully qualified contract name back to contract name ... using new access to the contract metadata --- .../org/ethereum/core/ImportLightTest.java | 26 +++++++++---------- .../org/ethereum/core/TransactionTest.java | 8 +++--- .../org/ethereum/solidity/CompilerTest.java | 26 +++++++++++++------ .../util/StandaloneBlockchainTest.java | 6 ++--- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java index 2501db893f..d77774d7a6 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/ImportLightTest.java @@ -19,13 +19,11 @@ import org.ethereum.config.CommonConfig; import org.ethereum.config.SystemProperties; -import org.ethereum.config.blockchain.FrontierConfig; import org.ethereum.core.genesis.GenesisLoader; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.datasource.inmem.HashMapDB; import org.ethereum.datasource.NoDeleteSource; -import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.IndexedBlockStore; import org.ethereum.db.RepositoryRoot; import org.ethereum.listener.EthereumListenerAdapter; @@ -372,7 +370,7 @@ public void createContractFork() throws Exception { "}"; StandaloneBlockchain bc = new StandaloneBlockchain(); - SolidityContract parent = bc.submitNewContract(contractSrc, ":Parent"); + SolidityContract parent = bc.submitNewContract(contractSrc, "Parent"); Block b1 = bc.createBlock(); Block b2 = bc.createBlock(); parent.callFunction("createChild", 100); @@ -380,7 +378,7 @@ public void createContractFork() throws Exception { 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, "Child", childAddress); child.callFunction("sum"); Block b4 = bc.createBlock(); Assert.assertEquals(BigInteger.valueOf(100 + 333 + 100 + 444), child.callConstFunction("c")[0]); @@ -407,9 +405,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, "A"); Block b3 = bc.createBlock(); - SolidityContract b = bc.submitNewContract(contractSrc, ":B"); + SolidityContract b = bc.submitNewContract(contractSrc, "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 +439,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, "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, "B", childAddress); BigInteger val = (BigInteger) b.callConstFunction("valReceived")[0]; Assert.assertEquals(20, val.longValue()); } @@ -502,7 +500,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, "A"); bc.createBlock(); { @@ -558,7 +556,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, "A"); bc.createBlock(); a.callFunction("recursive"); bc.createBlock(); @@ -647,7 +645,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, "A"); bc.createBlock(); a.callFunction("f"); bc.createBlock(); @@ -770,7 +768,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, "A"); bc.createBlock(); final BigInteger[] refund = new BigInteger[1]; bc.addEthereumListener(new EthereumListenerAdapter() { @@ -803,7 +801,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, "A"); bc.createBlock(); final List logs = new ArrayList<>(); bc.addEthereumListener(new EthereumListenerAdapter() { @@ -838,7 +836,7 @@ public void ecRecoverTest() throws Exception { "}"; StandaloneBlockchain bc = new StandaloneBlockchain().withGasLimit(5_000_000); - SolidityContract a = bc.submitNewContract(contractA, ":A"); + SolidityContract a = bc.submitNewContract(contractA, "A"); bc.createBlock(); ECKey key = ECKey.fromPrivate(BigInteger.ONE); diff --git a/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java b/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java index d3110bc607..a7ae74faf1 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/TransactionTest.java @@ -576,14 +576,14 @@ public void multiSuicideTest() throws IOException, InterruptedException { ECKey sender = ECKey.fromPrivate(Hex.decode("3ec771c31cac8c0dba77a69e503765701d3c2bb62435888d4ffa38fed60c445c")).compress(); System.out.println("address: " + Hex.toHexString(sender.getAddress())); - if (cres.contracts.get(":PsychoKiller") != null) { + if (cres.getContract("PsychoKiller") != null) { Transaction tx = createTx(blockchain, sender, new byte[0], - Hex.decode(cres.contracts.get(":PsychoKiller").bin)); + Hex.decode(cres.getContract("PsychoKiller").bin)); executeTransaction(blockchain, tx); byte[] contractAddress = tx.getContractAddress(); - CallTransaction.Contract contract1 = new CallTransaction.Contract(cres.contracts.get(":PsychoKiller").abi); + CallTransaction.Contract contract1 = new CallTransaction.Contract(cres.getContract("PsychoKiller").abi); byte[] callData = contract1.getByName("multipleHomocide").encode(); Transaction tx1 = createTx(blockchain, sender, contractAddress, callData, 0l); @@ -662,7 +662,7 @@ public void receiptErrorTest() throws Exception { contract.getBytes(), true, SolidityCompiler.Options.ABI, SolidityCompiler.Options.BIN); System.out.println(res.errors); CompilationResult cres = CompilationResult.parse(res.output); - Transaction tx = createTx(blockchain, sender, new byte[0], Hex.decode(cres.contracts.get(":GasConsumer").bin), 0); + Transaction tx = createTx(blockchain, sender, new byte[0], Hex.decode(cres.getContract("GasConsumer").bin), 0); TransactionReceipt receipt = executeTransaction(blockchain, tx).getReceipt(); receipt = new TransactionReceipt(receipt.getEncoded()); diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index f65d9fe6f4..417219db83 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -27,6 +27,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; +import java.util.HashMap; import static org.ethereum.solidity.compiler.SolidityCompiler.Options.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -68,8 +69,8 @@ public void simpleTest() throws IOException { System.out.println("Out: '" + res.output + "'"); System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - if (result.contracts.get(":a") != null) - System.out.println(result.contracts.get(":a").bin); + if (result.getContract("a") != null) + System.out.println(result.getContract("a").bin); else Assert.fail(); } @@ -88,7 +89,7 @@ public void defaultFuncTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(":a"); + CompilationResult.ContractMetadata a = result.getContract("a"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } @@ -103,7 +104,10 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test1"); + Assert.assertEquals("test1", result.getContractName()); + Assert.assertEquals(source.toAbsolutePath(), result.getContractPath()); + + CompilationResult.ContractMetadata a = result.getContract(source, "test1"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } @@ -117,7 +121,13 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test2"); + HashMap expected = new HashMap() {{ + put(source.getParent().resolve("file1.sol").toAbsolutePath(),"test1"); + put(source.toAbsolutePath(),"test2"); + }}; + Assert.assertEquals(expected, result.getContractKeys()); + + CompilationResult.ContractMetadata a = result.getContract(source, "test2"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } @@ -132,7 +142,7 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); + CompilationResult.ContractMetadata a = result.getContract(source, "test3"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } @@ -147,7 +157,7 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); + CompilationResult.ContractMetadata a = result.getContract(source, "test3"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } @@ -162,7 +172,7 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - CompilationResult.ContractMetadata a = result.contracts.get(source.toAbsolutePath().toString() + ":test3"); + CompilationResult.ContractMetadata a = result.getContract("test3"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); } diff --git a/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java b/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java index a78f6d6bf6..3132a9c6d7 100644 --- a/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/util/StandaloneBlockchainTest.java @@ -50,7 +50,7 @@ public void constructorTest() { " uint public b;" + " function A(uint a_, uint b_) {a = a_; b = b_; }" + "}", - ":A", 555, 777 + "A", 555, 777 ); Assert.assertEquals(BigInteger.valueOf(555), a.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(777), a.callConstFunction("b")[0]); @@ -61,7 +61,7 @@ public void constructorTest() { " uint public b;" + " function A(string a_, uint b_) {a = a_; b = b_; }" + "}", - ":A", "This string is longer than 32 bytes...", 777 + "A", "This string is longer than 32 bytes...", 777 ); Assert.assertEquals("This string is longer than 32 bytes...", b.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(777), b.callConstFunction("b")[0]); @@ -98,7 +98,7 @@ public void fixedSizeArrayTest() { " address public c;" + " address public d;" + " function A(uint[2] arr, address a1, address a2) {a = arr[0]; b = arr[1]; c = a1; d = a2;}" + - "}", ":A", + "}", "A", new Integer[]{111, 222}, addr1.getAddress(), addr2.getAddress()); Assert.assertEquals(BigInteger.valueOf(111), a.callConstFunction("a")[0]); Assert.assertEquals(BigInteger.valueOf(222), a.callConstFunction("b")[0]); From 6f295215db8b3bd6f879cfae7e19501c9f9f1af3 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Fri, 2 Mar 2018 13:53:31 -0500 Subject: [PATCH 10/13] Adding new methods to access the contract metadata --- .../samples/CreateContractSample.java | 4 +- .../ethereum/samples/EventListenerSample.java | 4 +- .../solidity/compiler/CompilationResult.java | 61 ++++++++++++++++++- .../util/blockchain/StandaloneBlockchain.java | 10 +-- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/samples/CreateContractSample.java b/ethereumj-core/src/main/java/org/ethereum/samples/CreateContractSample.java index 9ad6bbd028..5e51e6bab0 100644 --- a/ethereumj-core/src/main/java/org/ethereum/samples/CreateContractSample.java +++ b/ethereumj-core/src/main/java/org/ethereum/samples/CreateContractSample.java @@ -75,10 +75,10 @@ public void onBlock(Block block, List receipts) { throw new RuntimeException("Contract compilation failed:\n" + result.errors); } CompilationResult res = CompilationResult.parse(result.output); - if (res.contracts.isEmpty()) { + if (res.getContracts().isEmpty()) { throw new RuntimeException("Compilation failed, no contracts returned:\n" + result.errors); } - CompilationResult.ContractMetadata metadata = res.contracts.values().iterator().next(); + CompilationResult.ContractMetadata metadata = res.getContracts().iterator().next(); if (metadata.bin == null || metadata.bin.isEmpty()) { throw new RuntimeException("Compilation failed, no binary returned:\n" + result.errors); } diff --git a/ethereumj-core/src/main/java/org/ethereum/samples/EventListenerSample.java b/ethereumj-core/src/main/java/org/ethereum/samples/EventListenerSample.java index 4b70110afc..8ba0e397c4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/samples/EventListenerSample.java +++ b/ethereumj-core/src/main/java/org/ethereum/samples/EventListenerSample.java @@ -343,10 +343,10 @@ private CompilationResult.ContractMetadata compileContract() throws IOException throw new RuntimeException("Contract compilation failed:\n" + result.errors); } CompilationResult res = CompilationResult.parse(result.output); - if (res.contracts.isEmpty()) { + if (res.getContracts().isEmpty()) { throw new RuntimeException("Compilation failed, no contracts returned:\n" + result.errors); } - CompilationResult.ContractMetadata metadata = res.contracts.values().iterator().next(); + CompilationResult.ContractMetadata metadata = res.getContracts().iterator().next(); if (metadata.bin == null || metadata.bin.isEmpty()) { throw new RuntimeException("Compilation failed, no binary returned:\n" + result.errors); } diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java index 02b7bca3ef..cebc5d1d94 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java @@ -17,20 +17,26 @@ */ package org.ethereum.solidity.compiler; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.stream.Collectors; @JsonIgnoreProperties(ignoreUnknown = true) public class CompilationResult { - public Map contracts; - public String version; + @JsonProperty("contracts") private Map contracts; + @JsonProperty("version") public String version; - public static CompilationResult parse(String rawJson) throws IOException { + @JsonIgnore public static CompilationResult parse(String rawJson) throws IOException { if(rawJson == null || rawJson.isEmpty()){ CompilationResult empty = new CompilationResult(); empty.contracts = Collections.emptyMap(); @@ -42,6 +48,55 @@ public static CompilationResult parse(String rawJson) throws IOException { } } + @JsonIgnore public Path getContractPath() { + if (contracts.size() > 1) { + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + } else { + String key = contracts.keySet().iterator().next(); + return Paths.get(key.substring(0, key.lastIndexOf(':'))); + } + } + + @JsonIgnore public String getContractName() { + if (contracts.size() > 1) { + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + } else { + String key = contracts.keySet().iterator().next(); + return key.substring(key.lastIndexOf(':') + 1); + } + } + + @JsonIgnore public Map getContractKeys() { + return contracts.keySet().stream().collect(Collectors.toMap( + key -> Paths.get(key.substring(0, key.lastIndexOf(':'))), + key -> key.substring(key.lastIndexOf(':') + 1) + )); + } + + @JsonIgnore public ContractMetadata getContract(String contractName) { + if (contractName == null && contracts.size() == 1) { + return contracts.values().iterator().next(); + } else if (contractName == null || contractName.isEmpty()) { + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + } + for (Map.Entry entry : contracts.entrySet()) { + String key = entry.getKey(); + String name = key.substring(key.lastIndexOf(':') + 1); + if (contractName.equals(name)) { + return entry.getValue(); + } + } + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify a valid contract name. Available keys (" + getContractKeys().values() + ")."); + } + + @JsonIgnore public ContractMetadata getContract(Path contractPath, String contractName) { + return contracts.get(contractPath.toAbsolutePath().toString() + ':' + contractName); + } + + @JsonIgnore public Collection getContracts() { + return contracts.values(); + } + @JsonIgnoreProperties(ignoreUnknown = true) public static class ContractMetadata { public String abi; diff --git a/ethereumj-core/src/main/java/org/ethereum/util/blockchain/StandaloneBlockchain.java b/ethereumj-core/src/main/java/org/ethereum/util/blockchain/StandaloneBlockchain.java index 3cd49ed270..7965727824 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/blockchain/StandaloneBlockchain.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/blockchain/StandaloneBlockchain.java @@ -381,11 +381,7 @@ private SolidityContractImpl createContract(String soliditySrc, String contractN private SolidityContractImpl createContractFromJson(String contractName, String json) throws IOException { CompilationResult result = CompilationResult.parse(json); if (contractName == null) { - if (result.contracts.size() > 1) { - throw new RuntimeException("Source contains more than 1 contact (" + result.contracts.keySet() + "). Please specify the contract name"); - } else { - contractName = result.contracts.keySet().iterator().next(); - } + contractName = result.getContractName(); } return createContract(contractName, result); @@ -397,10 +393,10 @@ private SolidityContractImpl createContractFromJson(String contractName, String * @return */ private SolidityContractImpl createContract(String contractName, CompilationResult result) { - ContractMetadata cMetaData = result.contracts.get(contractName); + ContractMetadata cMetaData = result.getContract(contractName); SolidityContractImpl contract = createContract(cMetaData); - for (CompilationResult.ContractMetadata metadata : result.contracts.values()) { + for (CompilationResult.ContractMetadata metadata : result.getContracts()) { contract.addRelatedContract(metadata.abi); } return contract; From 351b0c290959e015e28375c6dd7a920d10d5ef95 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Fri, 2 Mar 2018 19:26:08 -0500 Subject: [PATCH 11/13] Returning the contracts and keys as type List --- .../solidity/compiler/CompilationResult.java | 27 +++++++++---------- .../org/ethereum/solidity/CompilerTest.java | 10 ++++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java index cebc5d1d94..52f0b86bc1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java @@ -25,10 +25,10 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collection; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.stream.Collectors; @JsonIgnoreProperties(ignoreUnknown = true) public class CompilationResult { @@ -50,7 +50,7 @@ public class CompilationResult { @JsonIgnore public Path getContractPath() { if (contracts.size() > 1) { - throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); } else { String key = contracts.keySet().iterator().next(); return Paths.get(key.substring(0, key.lastIndexOf(':'))); @@ -59,25 +59,18 @@ public class CompilationResult { @JsonIgnore public String getContractName() { if (contracts.size() > 1) { - throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); } else { String key = contracts.keySet().iterator().next(); return key.substring(key.lastIndexOf(':') + 1); } } - @JsonIgnore public Map getContractKeys() { - return contracts.keySet().stream().collect(Collectors.toMap( - key -> Paths.get(key.substring(0, key.lastIndexOf(':'))), - key -> key.substring(key.lastIndexOf(':') + 1) - )); - } - @JsonIgnore public ContractMetadata getContract(String contractName) { if (contractName == null && contracts.size() == 1) { return contracts.values().iterator().next(); } else if (contractName == null || contractName.isEmpty()) { - throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys().values() + ")."); + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); } for (Map.Entry entry : contracts.entrySet()) { String key = entry.getKey(); @@ -86,15 +79,19 @@ public class CompilationResult { return entry.getValue(); } } - throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify a valid contract name. Available keys (" + getContractKeys().values() + ")."); + throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify a valid contract name. Available keys (" + getContractKeys() + ")."); } @JsonIgnore public ContractMetadata getContract(Path contractPath, String contractName) { return contracts.get(contractPath.toAbsolutePath().toString() + ':' + contractName); } - @JsonIgnore public Collection getContracts() { - return contracts.values(); + @JsonIgnore public List getContracts() { + return new ArrayList<>(contracts.values()); + } + + @JsonIgnore public List getContractKeys() { + return new ArrayList<>(contracts.keySet()); } @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index 417219db83..550d8bb2d4 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -26,8 +26,9 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.List; import static org.ethereum.solidity.compiler.SolidityCompiler.Options.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -121,9 +122,10 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - HashMap expected = new HashMap() {{ - put(source.getParent().resolve("file1.sol").toAbsolutePath(),"test1"); - put(source.toAbsolutePath(),"test2"); + List expected = new ArrayList() {{ + // Interestingly the Solidity compiler returns a mishmash of path notations + add(source.getParent().resolve("file1.sol").toUri().getPath().substring(1) + ":test1"); + add(source.toAbsolutePath() +":test2"); }}; Assert.assertEquals(expected, result.getContractKeys()); From c1294de90f2d9e8b35f79745135f0cabe5af34db Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Fri, 2 Mar 2018 20:48:41 -0500 Subject: [PATCH 12/13] Removing this part of the test ... not platform independent ... expecting this to change anyway --- .../test/java/org/ethereum/solidity/CompilerTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index 550d8bb2d4..fe90f1df15 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -26,9 +26,7 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; import static org.ethereum.solidity.compiler.SolidityCompiler.Options.*; import static org.hamcrest.MatcherAssert.assertThat; @@ -122,13 +120,6 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); - List expected = new ArrayList() {{ - // Interestingly the Solidity compiler returns a mishmash of path notations - add(source.getParent().resolve("file1.sol").toUri().getPath().substring(1) + ":test1"); - add(source.toAbsolutePath() +":test2"); - }}; - Assert.assertEquals(expected, result.getContractKeys()); - CompilationResult.ContractMetadata a = result.getContract(source, "test2"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString()); From ccbadb446a2ae25e263ed168bb865e064d652cf2 Mon Sep 17 00:00:00 2001 From: Thomas Glaeser Date: Fri, 9 Mar 2018 11:12:38 -0500 Subject: [PATCH 13/13] Adding JavaDoc ... more assertions with test --- .../solidity/compiler/CompilationResult.java | 23 ++++++++++++++++++- .../org/ethereum/solidity/CompilerTest.java | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java index 52f0b86bc1..c5dd28453c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java +++ b/ethereumj-core/src/main/java/org/ethereum/solidity/compiler/CompilationResult.java @@ -48,6 +48,9 @@ public class CompilationResult { } } + /** + * @return the contract's path given this compilation result contains exactly one contract + */ @JsonIgnore public Path getContractPath() { if (contracts.size() > 1) { throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); @@ -57,6 +60,9 @@ public class CompilationResult { } } + /** + * @return the contract's name given this compilation result contains exactly one contract + */ @JsonIgnore public String getContractName() { if (contracts.size() > 1) { throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); @@ -66,6 +72,10 @@ public class CompilationResult { } } + /** + * @param contractName The contract name + * @return the first contract found for a given contract name; use {@link #getContract(Path, String)} if this compilation result contains more than one contract with the same name + */ @JsonIgnore public ContractMetadata getContract(String contractName) { if (contractName == null && contracts.size() == 1) { return contracts.values().iterator().next(); @@ -79,17 +89,28 @@ public class CompilationResult { return entry.getValue(); } } - throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify a valid contract name. Available keys (" + getContractKeys() + ")."); + throw new UnsupportedOperationException("No contract found with name '" + contractName + "'. Please specify a valid contract name. Available keys (" + getContractKeys() + ")."); } + /** + * @param contractPath The contract path + * @param contractName The contract name + * @return the contract with key {@code contractPath:contractName} if it exists; {@code null} otherwise + */ @JsonIgnore public ContractMetadata getContract(Path contractPath, String contractName) { return contracts.get(contractPath.toAbsolutePath().toString() + ':' + contractName); } + /** + * @return all contracts from this compilation result + */ @JsonIgnore public List getContracts() { return new ArrayList<>(contracts.values()); } + /** + * @return all keys from this compilation result + */ @JsonIgnore public List getContractKeys() { return new ArrayList<>(contracts.keySet()); } diff --git a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java index fe90f1df15..535ae4e273 100644 --- a/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/solidity/CompilerTest.java @@ -135,6 +135,10 @@ public void compileFilesTest() throws IOException { System.out.println("Err: '" + res.errors + "'"); CompilationResult result = CompilationResult.parse(res.output); + Assert.assertEquals(2, result.getContractKeys().size()); + Assert.assertEquals(result.getContract("test3"), result.getContract(source,"test3")); + Assert.assertNotNull(result.getContract("test1")); + CompilationResult.ContractMetadata a = result.getContract(source, "test3"); CallTransaction.Contract contract = new CallTransaction.Contract(a.abi); System.out.print(contract.functions[0].toString());