From 7ec858a7988b3d9d2710fa63b97fc822f7dd128b Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Wed, 10 Jul 2019 16:10:12 +0800 Subject: [PATCH] modify contract's classloader for check load classes! --- .../contract/maven/ContractResolveEngine.java | 46 ++++++---- .../JVMContractEventSendOperationHandle.java | 9 -- source/ledger/ledger-model/pom.xml | 1 - .../jd/blockchain/runtime/RuntimeContext.java | 80 ++++++++++++++++-- .../src/main/resources/black.config | 2 + .../sdk/samples/SDK_Contract_Check_Demo.java | 67 +++++++++++++++ .../jd/chain/contracts/ContractTestInf.java | 14 +++ .../src/main/resources/contract-jdchain.jar | Bin 0 -> 4255 bytes 8 files changed, 188 insertions(+), 31 deletions(-) create mode 100644 source/runtime/runtime-context/src/main/resources/black.config create mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java create mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java create mode 100644 source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar 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 0000000000000000000000000000000000000000..b9e41e1d09cd6d88abc22d12856c0c182752047c GIT binary patch literal 4255 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