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 - .../com/jd/blockchain/runtime/RuntimeContext.java | 80 +++++++++++++++++++-- .../src/main/resources/black.config | 2 + .../sdk/samples/SDK_Contract_Check_Demo.java | 67 +++++++++++++++++ .../com/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 zcmV;Q5Mb|6O9KQ7000O80O@w>P5=M^000000000000{sD08K?yK`lv6Mlb%#002-+ z0|XQR00;;GU|Q-&@I$@HO~qj^0e(ELKXTSB{gAEijv;#9x8U zMdW<=<-PNreTK8l=H*X^Ts=uzh3$4bdv~b=F3!%*oj=|`e8L$LVo@d)VLmj&CB2e* z^nv?CX_(J0KOgdVl0jj#w4aU73r{cRrbGZ!UbV7IgrXtw)qUWt1Aj#*vk;w7AY7+0 zRtH3aXDM2Ip4jWaUdG(t=s4FYhiYfD=N@jkeQAHZd$@b|>CSaZbAicef^ricK>V9= z(D+@aWt+{qz!Q$Q=o20U}%_A;Y!U`w6}AMOk>Jk1LPH|A4M zRUCo=AdDa8jWg^Y8VtqVk3j7WHACgLHBu@}0i?hJq;_p<+dtRK_70Q8bV-(E&oOrQ zJ0w!AC1?8?qP?Y$*gQnIr2z!4Q#{v*oF=3Lfj-B&E?gOGEELD)Sa3U*#{O%LH2D>0 z5vskBp*Fv=EHl)G(aIEsTxz;tfthR|;cn7}{!8XqMey(r=y23gNTW>X0@NQbcB(<_ zE|Xi1O&T|O+jE4D;Gie2mOD=sP3WJ1EQ}>ey?Wm79>6k-JS8&7k1YQ`kk^Xuet=X! zQGUzWyXN8G--%#|S~epqTYs;ekPO>@(cU>PF-)gO`z6E ztgc_3uz<+bwM&^FX8|h97)~N}JvqudJ#|hWK`MJqwph?g^FebtlOecrL(_aYX?RvY zzwo*D&W=b4$uj;vJ#U(xNr9YzwOIbAnUu@$v8zywqhk3h#{J#E;mDw5?6=tsy=T-V3 zd0nEoF2-batYZ!!Bw4I-gp&@LaW;O!$FG6^@A`LCJ=W#%o3zME;a^{gdUQ%JdAaN2 zF&a#fzGHMPvi!1PzGBR(Z(rWuP)h>@3IG5I008KA>P`Rv0000000000 z000L7003ieZ7*tMFHlPZ1PTBE2mk=-cIr+500000000000000X0000@MN~m8Nlr#D zZDDq0ZZBhRZ7ynLE@EtNV{2n*VQFqJP)h>@3IG5I008KA>P`Rv0000000000000C4 z003ieZ7)zu0|W{H00;m8>2~T)0000000000000004*&oFO+{2eElEyBFKuCVWo|D} zO9KQ7000O80O)q=P5=M^000000000002crN0Ap`$FKT2jV`yP%ZZBhRZgg^CV{~&b zP)h>@6aWAS2mtAJ>Q13Gq05{A006=O000yK002!zR6#9CPDU?HK~70VMN?ERO-4nI z%L;=q6h!xd{6l^q7exx`w2>##n{A~d&Qzg|Io|0pc^S^gTkcb+tf1(tyqt%a;$(I z6rY~tdwG3Lm5`nDGN+_R<9KT^#)=6)!9{}58w2583Mf*9_M48|-Odf&G+Rn2c>+*N z0|XQR00;;G=yvK(AXz5pc>n+aegFUfKmY&$O+{2eElEyBFKuCVWo|EHZ*4AWWG-TC zZ)0m?Xklq?FJo_RbaG*1bS-0VZE$I9WiN1VZ7y(fZ*XODbZKRCQ+7|yOD#$)Nlj5m zs#NezEKAMfQVs|5yh?Kv3=I?vO{`2!tqjc+oP$FYj0_Adxyn+DiZk=`Yz_4c^o;d_ zTzy;}gI&4Oi}FhgJX36w^KGSd>1OTdzOB}G7{E>KlL zW=<*>08mQ<1PTBE2mk=+cIr+500000000000000D0001EZ*4DXWG`cAVQFqJP)h>@ z3IG5I008NB>P`Rv0000000000001%o002!zR6#9CPDU?nVRmJ1FJo_QE^1^hVr*|? zYh!3(X>KoLZ*FvQVPkYHV{dJ6X>4ULP)h>@6aWAS2mt7I>Q374gv-(b003?U001xm z003ieZ7*tMFJow7X>KoLZ*FvQVPkZ2FGFu`baG*1bW~+?bV+VzNo{a!E@NzAb90SU z=}y}~5dM}N4#wPsqg;U&8bZK5=*iJSC~as+DuO_$zcz^pjvPC397Nx$?T>(p+6U-E zRh_j1p^!?*(#-7cH{YD{?>|3&0a!vtMgUP6bBMKL9`O(sBrM8M@kqvFJdyBJMo1t+ zSd#EeMhBuHJQwM%WrpC2ZtBh&gD*O_&)`p31&yIQrJGv1R?cbm9?uzc z)0eXH+}P)~F3ychzjLft8RDtDRaQ#{HGj-?Q_WkZWAnUIRTB+sPpdjf^C(%a7!)#4 zv31j77>uS${Di9pH;Zc4q08cO(oMqTWjExlXG)V7>4_y7I&5whta9R*+mu5%nw)Ei zFY{BX(!*YH)*RhXcilU}w0o~qFN2)5YIa`R(nWp4Eeco^1Pb~wAYnzpD%K>tQScV) zR8g7|kE}*!s`1Er(X%3*GDA-@vrMj}TNnCO-Cz=PDm%* zsA-uau~Yx7K?6Z<{VmvNFWglmzm*od`1!vj+)7F^wNvU5rR}E#Xlg-Tsc2?_VW9=_ z?M5_aN=##|_PF^Ra;(c14@6ru6jSJ>{{t;L{VaT>X-`Rp>7+=VGB5>%N&mQ{6&JoPkAssYXyIizF zT%8!FlVFc{3=MW+jnNx(tqDw$CnL;MBce@bKk4ZUgbvTpz7rp*%hd=j)BA{ZviZjVYqWJeI4d)AUVJj1X0K9}md0i&`{8ccNXhF4x1qP)h>@6aWAS z2mt7I>Q44|cOdit004{u001li003ieZ7*tMFJow7X>KoLZ*FvQVPkZ2FGFu`baG*1 zbW~+?bV+VzE@NzAb90SO%}T>S5dNl36K(wIK?NT`X+5|XZ#_v-2owY>y>GT_yD^!S z&9)Ecp%36gi5qPZ?Zts%e!icX_m8(VfE)A@93?m=bY7idPdMw33%Qb_lsp#`AC~iB zHkcC5AD8S+rKhGgd8u!it(V?dt_fFTWh+t4L|$6;q88GyP?o)u%8Svaxm#)WLqf!| z(uCAWp4n=&kS;i!_Orq6VM6@PB6KHq>6E@VWze2%J)d;#Gk(5ql!S}_yb(+2~T)0000000000000006aWAKO+{2eElEyBFGEjGR8m1hR4z?M%SbHF zu*xzm@yqlv^2#f$Fi#0}v&b(gGP5=M^000000000000{sD0000000000 z000000000@MN~m8Nlr#D{>lIVP)h*<6aW+e00;;GU|Q-KoLZ*FvQ zVPkYHV{dJ6X>4ULaBpoccx`M@O9283015yA2mk=+cIr+500000000000000700000 z00000000000F49y0Ap`$FKT2jP)h*<3IGZK00;m8>2~T)000000000000000ApigX z0000000000006QC002!zR6#9CPDU?nVRmJ1FJo_QE^1^hVr*|?Yh!3(X>Ko2O9283 z015yA2mk=+cIr+50000000000000040000000000000000PzF>0Ap`$FHlPX0tx^M z000O80O@w>P5=M^000000000001p5F00000000000000J1poj|MN~m8Nlr#DZDDq0 zZZA+v0RjpD3IG5I008KA>P`Rv0000000000000*N000000000000000Km`B*V{dIQ zYGf~CXklq?FJo_RbaG*1baO9IO928D02BZK2nYb_cIr-{HKEI#0002O0000K00000 z00000000000Cfcb08K?yK`lv6MlVf4PDw^ZQ&cWZMo>!u0u%rg000OG0O)q=P9Rw( z=y?DD0Db@f06+i$00000000000000(1^@s}MN~m8Nlr#DZDDq0ZZBhRZ7ynLE@EtN zV{2n*VQFqJV{dMBa$#e1En{zOaA|C1FK};dE^u;haAk6IX=QUzO9283015yA2mk=+ zcIr+500000000000000D00000000000000002&7X0Ap`$FKT2jV`yP%ZZA+v0RjpD z3IG5I008NB>P`Rv0000000000001%o000000000000000MF#)?O+{2eElEyBFKuCV zWo|EHZ*4AWWG-TCZ)0m?Xklq?FJo_RbaG*1bS-0VZE$I9WiL=m0Rj{N6aWAS2mt7I z>Q374gv-(b003?U001xm000000000000000l?MO-V{dIQYGf~CXklq?FJo_RbaG*1 zbaO95Z*FvQVPkYuWpi{%Ze~esaBMDPY+-YAP)h*<6aW+e00;;G=yvK(_IGz6^Z)<= zi~#@uEC2ui0000000000006ZL003ieZ7*tMFJow7X>KoLZ*FvQVPkZ2FGFu`baG*1 zbW~+?bV+VzE@NzAb8}Ej0Rj{N6aWYa2mtAJ>Q3%ScONwX001)p000yK0000000000 z00000^9uj~O+{2eElEyBFGEjGR8m1hR4z?MP)h{{000004gd}S9|QmZY777X004et B8K(dM literal 0 KcmV+b0RR6000031