@@ -41,6 +41,20 @@ public class ContractResolveEngine { | |||||
private static final String BLACK_NAME_LIST = "black.name.list"; | 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 Log LOGGER; | ||||
private MavenProject project; | private MavenProject project; | ||||
@@ -87,14 +101,6 @@ public class ContractResolveEngine { | |||||
throw e; | 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); | LinkedList<String> totalClassList = loadAllClass(jarFile); | ||||
// 该项目路径 | // 该项目路径 | ||||
String projectDir = project.getBasedir().getPath(); | String projectDir = project.getBasedir().getPath(); | ||||
@@ -230,34 +236,32 @@ public class ContractResolveEngine { | |||||
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", jarFile.getName())); | 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); | return blackList(config, BLACK_NAME_LIST); | ||||
} | } | ||||
private Set<String> blackClassSet(Properties config) { | |||||
private static Set<String> blackClassSet(Properties config) { | |||||
Set<String> blackClassSet = new HashSet<>(); | Set<String> blackClassSet = new HashSet<>(); | ||||
String attrProp = config.getProperty(BLACK_CLASS_LIST); | String attrProp = config.getProperty(BLACK_CLASS_LIST); | ||||
if (attrProp != null && attrProp.length() > 0) { | if (attrProp != null && attrProp.length() > 0) { | ||||
String[] attrPropArray = attrProp.split(","); | String[] attrPropArray = attrProp.split(","); | ||||
for (String attr : attrPropArray) { | for (String attr : attrPropArray) { | ||||
LOGGER.info(String.format("Config [%s] -> [%s]", BLACK_CLASS_LIST, attr)); | |||||
blackClassSet.add(attr.trim()); | blackClassSet.add(attr.trim()); | ||||
} | } | ||||
} | } | ||||
return blackClassSet; | return blackClassSet; | ||||
} | } | ||||
private List<ContractPackage> blackPackageList(Properties config) { | |||||
private static List<ContractPackage> blackPackageList(Properties config) { | |||||
return blackList(config, BLACK_PACKAGE_LIST); | 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<>(); | List<ContractPackage> list = new ArrayList<>(); | ||||
String attrProp = config.getProperty(attrName); | String attrProp = config.getProperty(attrName); | ||||
if (attrProp != null || attrProp.length() > 0) { | if (attrProp != null || attrProp.length() > 0) { | ||||
String[] attrPropArray = attrProp.split(","); | String[] attrPropArray = attrProp.split(","); | ||||
for (String attr : attrPropArray) { | for (String attr : attrPropArray) { | ||||
LOGGER.info(String.format("Config [%s] -> [%s]", attrName, attr)); | |||||
list.add(new ContractPackage(attr)); | list.add(new ContractPackage(attr)); | ||||
} | } | ||||
} | } | ||||
@@ -359,11 +363,21 @@ public class ContractResolveEngine { | |||||
return finalJar; | 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 properties = new Properties(); | ||||
properties.load(this.getClass().getClassLoader().getResourceAsStream(CONFIG)); | |||||
properties.load(ContractResolveEngine.class.getResourceAsStream(File.separator + CONFIG)); | |||||
return properties; | return properties; | ||||
} | } | ||||
@@ -39,13 +39,4 @@ public class JVMContractEventSendOperationHandle extends AbstractContractEventHa | |||||
} | } | ||||
return contractCode; | 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> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>crypto-classic</artifactId> | <artifactId>crypto-classic</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
<scope>test</scope> | |||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
@@ -2,11 +2,10 @@ package com.jd.blockchain.runtime; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | |||||
import java.net.URL; | import java.net.URL; | ||||
import java.net.URLClassLoader; | 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.concurrent.ConcurrentHashMap; | ||||
import java.util.jar.Attributes; | import java.util.jar.Attributes; | ||||
import java.util.jar.JarFile; | import java.util.jar.JarFile; | ||||
@@ -16,7 +15,7 @@ import com.jd.blockchain.utils.io.RuntimeIOException; | |||||
public abstract class RuntimeContext { | public abstract class RuntimeContext { | ||||
public static interface Environment{ | |||||
public static interface Environment { | |||||
boolean isProductMode(); | boolean isProductMode(); | ||||
@@ -24,6 +23,7 @@ public abstract class RuntimeContext { | |||||
private static final Object mutex = new Object(); | private static final Object mutex = new Object(); | ||||
private static volatile RuntimeContext runtimeContext; | private static volatile RuntimeContext runtimeContext; | ||||
public static RuntimeContext get() { | public static RuntimeContext get() { | ||||
@@ -202,8 +202,78 @@ public abstract class RuntimeContext { | |||||
@Override | @Override | ||||
protected URLClassLoader createDynamicModuleClassLoader(URL jarURL) { | 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); | |||||
} |