Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<feat>(contract): add merge abi logic, support merge 'as' and 'from' import, add event sample contracts. #855

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ jobs:
- run:
name: Setup dependencies
command: |
yum install -y epel-release centos-release-scl which python python-devel
cd /etc/yum.repos.d/
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
yum update -y
yum install -y git openssl-devel openssl java java-devel
- checkout
- run:
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/console/common/ConsoleUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,15 @@ public static void main(String[] args) {
}

public static Version convertStringToVersion(String version) {
return Version.valueOf("V" + version.replace('.', '_'));
try {
return Version.valueOf("V" + version.replace('.', '_'));
} catch (Exception e) {
System.out.println(
"Invalid solidity version: "
+ version
+ ", only support: "
+ Arrays.toString(Version.values()));
throw e;
}
}
}
17 changes: 11 additions & 6 deletions src/main/java/console/contract/ConsoleContractImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package console.contract;

import static console.contract.utils.ContractCompiler.mergeAbi;
import static console.contract.utils.ContractCompiler.mergeSource;
import static org.fisco.solc.compiler.SolidityCompiler.Options.ABI;
import static org.fisco.solc.compiler.SolidityCompiler.Options.BIN;
import static org.fisco.solc.compiler.SolidityCompiler.Options.METADATA;
Expand Down Expand Up @@ -30,6 +32,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -1073,27 +1076,30 @@ private String getSolidityAbi(String contractFileName) throws Exception {
if (!solFile.exists()) {
throw new Exception("The contract file " + contractFilePath + " doesn't exist!");
}
String contractName = solFile.getName().split("\\.")[0];

List<SolidityCompiler.Option> defaultOptions = Arrays.asList(ABI, BIN, METADATA);
List<SolidityCompiler.Option> options = new ArrayList<>(defaultOptions);

logger.debug(
"compileSolToBinAndAbi, solc version:{} ,basePath: {}",
Version.V0_8_11,
Version.V0_8_26,
solFile.getParentFile().getCanonicalPath());
SolidityCompiler.Option basePath =
new SolidityCompiler.CustomOption(
"base-path", solFile.getParentFile().getCanonicalPath());
options.add(basePath);
String fileName = solFile.getName();
String dir = solFile.getParentFile().getCanonicalPath() + File.separator;

String mergedSource = mergeSource(dir, fileName, new HashSet<>());

// compile ecdsa
SolidityCompiler.Result res =
SolidityCompiler.compile(
solFile,
mergedSource.getBytes(StandardCharsets.UTF_8),
(client.getCryptoType() == CryptoType.SM_TYPE),
true,
Version.V0_8_11,
Version.V0_8_26,
options.toArray(new SolidityCompiler.Option[0]));

if (logger.isDebugEnabled()) {
Expand All @@ -1111,8 +1117,7 @@ private String getSolidityAbi(String contractFileName) throws Exception {
}

CompilationResult result = CompilationResult.parse(res.getOutput());
CompilationResult.ContractMetadata contractMetadata = result.getContract(contractName);
return contractMetadata.abi;
return mergeAbi(result);
}

private String getWasmAbi(String groupId, String pwd, String contractFileName)
Expand Down
56 changes: 49 additions & 7 deletions src/main/java/console/contract/utils/ContractCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
import static org.fisco.solc.compiler.SolidityCompiler.Options.METADATA;
import static org.fisco.solc.compiler.SolidityCompiler.Options.USERDOC;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ArrayNode;
import console.common.ConsoleUtils;
import console.contract.exceptions.CompileContractException;
import console.contract.model.AbiAndBin;
Expand All @@ -38,6 +42,7 @@
import org.apache.commons.io.FileUtils;
import org.fisco.bcos.codegen.v3.exceptions.CodeGenException;
import org.fisco.bcos.codegen.v3.utils.CodeGenUtils;
import org.fisco.bcos.sdk.v3.utils.ObjectMapperFactory;
import org.fisco.bcos.sdk.v3.utils.StringUtils;
import org.fisco.evm.analysis.EvmAnalyser;
import org.fisco.solc.compiler.CompilationResult;
Expand Down Expand Up @@ -241,7 +246,8 @@ public static AbiAndBin compileSolToBinAndAbi(

String bin = sm ? "" : meta.bin;
String smBin = sm ? meta.bin : "";
AbiAndBin abiAndBin = new AbiAndBin(meta.abi, bin, smBin, meta.devdoc);
String abi = mergeAbi(result);
AbiAndBin abiAndBin = new AbiAndBin(abi, bin, smBin, meta.devdoc);

// evm static analysis
File abiFile = new File(abiDir + contractName + ".abi");
Expand All @@ -268,8 +274,11 @@ public static AbiAndBin compileSolToBinAndAbi(
}
}

String abi = FileUtils.readFileToString(abiFile, StandardCharsets.UTF_8);
abiAndBin.setAbi(abi);
// write abi and re-read abi for add evm analysis result
if (isContractParallelAnalysis) {
abi = FileUtils.readFileToString(abiFile, StandardCharsets.UTF_8);
abiAndBin.setAbi(abi);
}
checkBinaryCode(contractName, meta.bin);
return abiAndBin;
}
Expand All @@ -287,7 +296,10 @@ public static String mergeSource(String currentDir, String sourceFile, Set<Strin
throw new IOException("Source file:" + fullPath + " not found");
}

Pattern pattern = Pattern.compile("^\\s*import\\s+[\"'](.+)[\"']\\s*;\\s*$");
Pattern simpleImport = Pattern.compile("^\\s*import\\s+[\"'](.+)[\"']\\s*;\\s*$");
Pattern asImport = Pattern.compile("^\\s*import\\s+[\"'](.+)[\"']\\s*as\\s*(.+);\\s*$");
Pattern fromImport =
Pattern.compile("^\\s*import\\s+[\\w{}]*\\s+from\\s+['\"](.+)['\"];\\s*$");
try (Scanner scanner = new Scanner(sourceResource, "UTF-8")) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
Expand All @@ -305,9 +317,21 @@ public static String mergeSource(String currentDir, String sourceFile, Set<Strin
continue;
}

Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String depSourcePath = matcher.group(1);
Matcher simpleMatcher = simpleImport.matcher(line);
Matcher fromMatcher = fromImport.matcher(line);
Matcher asMatcher = asImport.matcher(line);
boolean simpleFlag = simpleMatcher.find();
boolean fromFlag = fromMatcher.find();
boolean asFlag = asMatcher.find();
if (simpleFlag || fromFlag || asFlag) {
String depSourcePath;
if (simpleFlag) {
depSourcePath = simpleMatcher.group(1);
} else if (fromFlag) {
depSourcePath = fromMatcher.group(1);
} else {
depSourcePath = asMatcher.group(1);
}
String nextPath = dir + depSourcePath;
if (nextPath.contains("./")) {
nextPath = new File(nextPath).getCanonicalPath();
Expand All @@ -326,6 +350,24 @@ public static String mergeSource(String currentDir, String sourceFile, Set<Strin
return sourceBuffer.toString();
}

public static String mergeAbi(CompilationResult result) throws JsonProcessingException {

List<String> contractNames = result.getContractKeys();
if (contractNames.isEmpty()) {
return null;
}
ObjectReader objectReader = ObjectMapperFactory.getObjectReader();
ArrayNode mainNode = (ArrayNode) objectReader.createArrayNode();
for (String contractName : contractNames) {
String key = contractName.substring(contractName.lastIndexOf(':') + 1);
JsonNode jsonNode = objectReader.readTree(result.getContract(key).abi);
if (jsonNode.isArray() && !jsonNode.isEmpty()) {
mainNode.addAll((ArrayNode) jsonNode);
}
}
return mainNode.toString();
}

public static void checkBinaryCode(String contractName, String binary)
throws CompileContractException {
String externalLibSplitter = "_";
Expand Down
20 changes: 20 additions & 0 deletions src/main/resources/contract/solidity/BaseEvent.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <=0.8.26;

contract BaseEvent {

//---------------------------------------------------------------------------------------------------------------
event Transfer(string indexed from_account, string indexed to_account, uint256 indexed amount);
event TransferAccount(string indexed from_account,string indexed to_account);
event TransferAmount(uint256 indexed amount);

function transfer(string memory from_account, string memory to_account, uint256 amount) public {

emit Transfer(from_account, to_account, amount);

emit TransferAccount(from_account, to_account);

emit TransferAmount(amount);

}
}
51 changes: 51 additions & 0 deletions src/main/resources/contract/solidity/EchoEvent.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.6.10 <=0.8.26;

contract BaseEvent {

//---------------------------------------------------------------------------------------------------------------
event Transfer(string indexed from_account, string indexed to_account, uint256 indexed amount);
event TransferAccount(string indexed from_account,string indexed to_account);
event TransferAmount(uint256 indexed amount);

function transfer(string memory from_account, string memory to_account, uint256 amount) public {

emit Transfer(from_account, to_account, amount);

emit TransferAccount(from_account, to_account);

emit TransferAmount(amount);

}
}

contract EchoEvent {

event Echo1(uint256 indexed u);
event Echo2(int256 indexed i);
event Echo3(string indexed s);
event Echo4(uint256 indexed u, int256 indexed i, string indexed s);

function echo(uint256 u, int256 i, string memory s) public returns(uint256, int256, string memory) {

emit Echo1(u);
emit Echo2(i);
emit Echo3(s);
emit Echo4(u, i ,s);

return (u, i , s);
}

event Echo5(bytes32 indexed bsn);
event Echo6(bytes indexed bs);
event Echo7(bytes32 indexed bsn, bytes indexed bs);

function echo(bytes32 bsn, bytes memory bs) public returns(bytes32, bytes memory) {

emit Echo5(bsn);
emit Echo6(bs);
emit Echo7(bsn, bs);

return (bsn, bs);
}
}
Loading