| @@ -41,6 +41,20 @@ public class ContractResolveEngine { | |||
| private static final String BLACK_NAME_LIST = "black.name.list"; | |||
| private static List<ContractPackage> blackNameList; | |||
| private static List<ContractPackage> blackPackageList; | |||
| private static Set<String> 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<ContractPackage> blackNameList = blackNameList(config); | |||
| List<ContractPackage> blackPackageList = blackPackageList(config); | |||
| Set<String> blackClassSet = blackClassSet(config); | |||
| LinkedList<String> 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<ContractPackage> blackNameList(Properties config) { | |||
| private static List<ContractPackage> blackNameList(Properties config) { | |||
| return blackList(config, BLACK_NAME_LIST); | |||
| } | |||
| private Set<String> blackClassSet(Properties config) { | |||
| private static Set<String> blackClassSet(Properties config) { | |||
| Set<String> 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<ContractPackage> blackPackageList(Properties config) { | |||
| private static List<ContractPackage> blackPackageList(Properties config) { | |||
| return blackList(config, BLACK_PACKAGE_LIST); | |||
| } | |||
| private List<ContractPackage> blackList(Properties config, String attrName) { | |||
| private static List<ContractPackage> blackList(Properties config, String attrName) { | |||
| List<ContractPackage> 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; | |||
| } | |||
| @@ -39,13 +39,4 @@ public class JVMContractEventSendOperationHandle extends AbstractContractEventHa | |||
| } | |||
| return contractCode; | |||
| } | |||
| // @Override | |||
| // public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, | |||
| // TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, | |||
| // OperationHandleContext handleContext, LedgerService ledgerService) { | |||
| // // TODO Auto-generated method stub | |||
| // return null; | |||
| // } | |||
| } | |||
| @@ -37,7 +37,6 @@ | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-classic</artifactId> | |||
| <version>${project.version}</version> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| @@ -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<String> BLACK_CLASSES = new HashSet<>(); | |||
| private static final Set<String> 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); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,2 @@ | |||
| java.util.Random, com.jd.blockchain.ledger.BlockchainKeyGenerator | |||
| java.io.*, java.nio.*, java.net.*, org.apache.commons.io.* | |||
| @@ -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<String> result = decode(contract.randomChars(1024)); | |||
| commit(txTpl); | |||
| String random = result.get(); | |||
| System.out.println(random); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||