Browse Source

modify contract's classloader for check load classes!

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
7ec858a798
8 changed files with 188 additions and 31 deletions
  1. +30
    -16
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java
  2. +0
    -9
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java
  3. +0
    -1
      source/ledger/ledger-model/pom.xml
  4. +75
    -5
      source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java
  5. +2
    -0
      source/runtime/runtime-context/src/main/resources/black.config
  6. +67
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java
  7. +14
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java
  8. BIN
      source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar

+ 30
- 16
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractResolveEngine.java View File

@@ -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;
} }


+ 0
- 9
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java View File

@@ -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;
// }

} }

+ 0
- 1
source/ledger/ledger-model/pom.xml View File

@@ -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>

+ 75
- 5
source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java View File

@@ -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);
}
}
} }
} }

+ 2
- 0
source/runtime/runtime-context/src/main/resources/black.config View File

@@ -0,0 +1,2 @@
java.util.Random, com.jd.blockchain.ledger.BlockchainKeyGenerator
java.io.*, java.nio.*, java.net.*, org.apache.commons.io.*

+ 67
- 0
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Check_Demo.java View File

@@ -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);
}


}

+ 14
- 0
source/sdk/sdk-samples/src/main/java/com/jd/chain/contracts/ContractTestInf.java View File

@@ -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);
}

BIN
source/sdk/sdk-samples/src/main/resources/contract-jdchain.jar View File


Loading…
Cancel
Save