diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java index 06619a84..3fb2404d 100644 --- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java @@ -41,6 +41,20 @@ public class ContractResolveEngine { private static final String BLACK_NAME_LIST = "black.name.list"; + private static List blackNameList; + + private static List blackPackageList; + + private static Set blackClassSet; + + static { + try { + configInit(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + private Log LOGGER; private MavenProject project; @@ -87,14 +101,6 @@ public class ContractResolveEngine { throw e; } - Properties config = loadConfig(); - - List blackNameList = blackNameList(config); - - List blackPackageList = blackPackageList(config); - - Set blackClassSet = blackClassSet(config); - LinkedList totalClassList = loadAllClass(jarFile); // 该项目路径 String projectDir = project.getBasedir().getPath(); @@ -230,34 +236,32 @@ public class ContractResolveEngine { LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", jarFile.getName())); } - private List blackNameList(Properties config) { + private static List blackNameList(Properties config) { return blackList(config, BLACK_NAME_LIST); } - private Set blackClassSet(Properties config) { + private static Set blackClassSet(Properties config) { Set blackClassSet = new HashSet<>(); String attrProp = config.getProperty(BLACK_CLASS_LIST); if (attrProp != null && attrProp.length() > 0) { String[] attrPropArray = attrProp.split(","); for (String attr : attrPropArray) { - LOGGER.info(String.format("Config [%s] -> [%s]", BLACK_CLASS_LIST, attr)); blackClassSet.add(attr.trim()); } } return blackClassSet; } - private List blackPackageList(Properties config) { + private static List blackPackageList(Properties config) { return blackList(config, BLACK_PACKAGE_LIST); } - private List blackList(Properties config, String attrName) { + private static List blackList(Properties config, String attrName) { List list = new ArrayList<>(); String attrProp = config.getProperty(attrName); if (attrProp != null || attrProp.length() > 0) { String[] attrPropArray = attrProp.split(","); for (String attr : attrPropArray) { - LOGGER.info(String.format("Config [%s] -> [%s]", attrName, attr)); list.add(new ContractPackage(attr)); } } @@ -359,11 +363,21 @@ public class ContractResolveEngine { return finalJar; } - private Properties loadConfig() throws Exception { + private static void configInit() throws Exception { + Properties config = loadConfig(); + + blackNameList = blackNameList(config); + + blackPackageList = blackPackageList(config); + + blackClassSet = blackClassSet(config); + } + + private static Properties loadConfig() throws Exception { Properties properties = new Properties(); - properties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG)); + properties.load(ContractResolveEngine.class.getResourceAsStream(File.separator + CONFIG)); return properties; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java index f32b7f41..b05e2189 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java @@ -39,13 +39,4 @@ public class JVMContractEventSendOperationHandle extends AbstractContractEventHa } return contractCode; } - -// @Override -// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, -// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, -// OperationHandleContext handleContext, LedgerService ledgerService) { -// // TODO Auto-generated method stub -// return null; -// } - } diff --git a/source/ledger/ledger-model/pom.xml b/source/ledger/ledger-model/pom.xml index 6c39c1cf..ea21a207 100644 --- a/source/ledger/ledger-model/pom.xml +++ b/source/ledger/ledger-model/pom.xml @@ -37,7 +37,6 @@ com.jd.blockchain crypto-classic ${project.version} - test diff --git a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java index 569a95a5..c37077e8 100644 --- a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java +++ b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java @@ -2,11 +2,10 @@ package com.jd.blockchain.runtime; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -16,7 +15,7 @@ import com.jd.blockchain.utils.io.RuntimeIOException; public abstract class RuntimeContext { - public static interface Environment{ + public static interface Environment { boolean isProductMode(); @@ -24,6 +23,7 @@ public abstract class RuntimeContext { private static final Object mutex = new Object(); + private static volatile RuntimeContext runtimeContext; public static RuntimeContext get() { @@ -202,8 +202,78 @@ public abstract class RuntimeContext { @Override protected URLClassLoader createDynamicModuleClassLoader(URL jarURL) { - return new URLClassLoader(new URL[] { jarURL }, RuntimeContext.class.getClassLoader()); + return new ContractURLClassLoader(jarURL, RuntimeContext.class.getClassLoader()); + } + + } + + static class ContractURLClassLoader extends URLClassLoader { + + private static final String BLACK_CONFIG = "black.config"; + + private static final Set BLACK_CLASSES = new HashSet<>(); + + private static final Set BLACK_PACKAGES = new HashSet<>(); + + static { + initBlacks(); + } + + public ContractURLClassLoader(URL contractJarURL, ClassLoader parent) { + super(new URL[] { contractJarURL }, parent); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (BLACK_CLASSES.contains(name)) { + throw new IllegalStateException(String.format("Contract cannot use Class [%s]", name)); + } else { + // 判断该包是否是黑名单 + String trimName = name.trim(); + String packageName = trimName.substring(0, trimName.length() - 2); + if (BLACK_PACKAGES.contains(packageName)) { + throw new IllegalStateException(String.format("Contract cannot use Class [%s]", name)); + } + } + return super.loadClass(name); } + private static void initBlacks() { + try { + InputStream inputStream = ContractURLClassLoader.class.getResourceAsStream(File.separator + BLACK_CONFIG); + String text = FileUtils.readText(inputStream); + String[] textArray = text.split("\n"); + for (String setting : textArray) { + // 支持按照逗号分隔 + if (setting == null || setting.length() == 0) { + continue; + } + String[] settingArray = setting.split(","); + for (String set : settingArray) { + String totalClass = set.trim(); + if (totalClass.endsWith("*")) { + // 说明是包,获取具体包名 + String packageName = totalClass.substring(0, totalClass.length() - 2); + BLACK_PACKAGES.add(packageName); + } else { + // 具体的类名,直接放入集合 + BLACK_CLASSES.add(totalClass); + } + } + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + public static void main(String[] args) { + for (String s : BLACK_CLASSES) { + System.out.println(s); + } + + for (String s : BLACK_PACKAGES) { + System.out.println(s); + } + } } } diff --git a/source/runtime/runtime-context/src/main/resources/black.config b/source/runtime/runtime-context/src/main/resources/black.config new file mode 100644 index 00000000..d3353498 --- /dev/null +++ b/source/runtime/runtime-context/src/main/resources/black.config @@ -0,0 +1,2 @@ +java.util.Random, com.jd.blockchain.ledger.BlockchainKeyGenerator +java.io.*, java.nio.*, java.net.*, org.apache.commons.io.* \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java new file mode 100644 index 00000000..7d521776 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java @@ -0,0 +1,67 @@ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.contract.TransferContract; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.transaction.GenericValueHolder; +import com.jd.blockchain.utils.Bytes; +import com.jd.chain.contracts.ContractTestInf; + +import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturnValue.decode; + +public class SDK_Contract_Check_Demo extends SDK_Base_Demo { + + public static void main(String[] args) { + new SDK_Contract_Check_Demo().executeContract(); + } + + public void executeContract() { + + // 发布jar包 + // 定义交易模板 + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + // 将jar包转换为二进制数据 + byte[] contractCode = readChainCodes("contract-jdchain.jar"); + + // 生成一个合约账号 + BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + + // 生成发布合约操作 + txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); + + // 生成预发布交易; + PreparedTransaction ptx = txTpl.prepare(); + + // 对交易进行签名 + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + // 获取合约地址 + Bytes contractAddress = contractDeployKey.getAddress(); + + // 打印交易返回信息 + System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", + txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), + txResp.isSuccess(), txResp.getExecutionState()); + + // 打印合约地址 + System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); + + // 执行合约 + exeContract(contractAddress); + } + + private void exeContract(Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + ContractTestInf contract = txTpl.contract(contractAddress, ContractTestInf.class); + GenericValueHolder result = decode(contract.randomChars(1024)); + commit(txTpl); + String random = result.get(); + System.out.println(random); + } + + +} diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java b/source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java new file mode 100644 index 00000000..7e5d362a --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java @@ -0,0 +1,14 @@ +package com.jd.chain.contracts; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +@Contract +public interface ContractTestInf { + + @ContractEvent(name = "print") + void print(String name, int age); + + @ContractEvent(name = "random") + String randomChars(int max); +} \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar b/source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar new file mode 100644 index 00000000..b9e41e1d Binary files /dev/null and b/source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar differ