From c147e7e786466356fdfb0a3b91e80a5761be8427 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 21 Oct 2019 15:00:46 +0800 Subject: [PATCH 1/4] =?UTF-8?q?Solve=20the=20bug=20that=20the=20contract?= =?UTF-8?q?=20plug-in=20file=20cannot=20be=20deleted=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/jd/blockchain/contract/ContractJarUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java index 775d0ec5..7786980e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java @@ -139,7 +139,12 @@ public class ContractJarUtils { if (inputStream == null) { throw new IllegalStateException(CONTRACT_MF + " IS NULL !!!"); } - byte[] bytes = IOUtils.toByteArray(inputStream); + byte[] bytes; + try { + bytes = IOUtils.toByteArray(inputStream); + } finally { + inputStream.close(); + } if (bytes == null || bytes.length == 0) { throw new IllegalStateException(CONTRACT_MF + " IS Illegal !!!"); } From 3078572052a454e5f2328def85d1a0a11803b8ed Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Mon, 21 Oct 2019 15:42:22 +0800 Subject: [PATCH 2/4] =?UTF-8?q?Solve=20the=20bug=20that=20the=20contract?= =?UTF-8?q?=20plug-in=20file=20cannot=20be=20deleted=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GatewayInterceptServiceHandler.java | 38 +++++++++++++++++++ .../blockchain/contract/ContractJarUtils.java | 25 +++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java index 44f22aad..e9651a2c 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java @@ -5,15 +5,26 @@ import com.jd.blockchain.gateway.PeerService; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.TransactionRequest; +import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.net.URL; @Service public class GatewayInterceptServiceHandler implements GatewayInterceptService { + private static String contractsPath; + @Autowired private PeerService peerService; + static { + contractsPath = jarRootDir(); + } + @Override public void intercept(TransactionRequest txRequest) { // 当前仅处理合约发布的请求 @@ -29,7 +40,34 @@ public class GatewayInterceptServiceHandler implements GatewayInterceptService { } private void contractCheck(final ContractCodeDeployOperation contractOP) { + // 校验chainCode ContractJarUtils.verify(contractOP.getChainCode()); } + + private static String jarRootDir() { + + try { + URL url = GatewayInterceptServiceHandler.class.getProtectionDomain().getCodeSource().getLocation(); + String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); + if (currPath.contains("!/")) { + currPath = currPath.substring(5, currPath.indexOf("!/")); + } + if (currPath.endsWith(".jar")) { + currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); + } + File file = new File(currPath); + + String homeDir = file.getParent(); + + String jarRootPath = homeDir + File.separator + "contracts"; + + FileUtils.forceMkdir(new File(jarRootPath)); + + return jarRootPath; + + } catch (Exception e) { + throw new IllegalStateException(e); + } + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java index 7786980e..50643d06 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java @@ -110,16 +110,16 @@ public class ContractJarUtils { return dotClassName; } - public static void verify(byte[] chainCode) { + public static void verify(String contractPath, byte[] chainCode) { if (chainCode == null || chainCode.length == 0) { throw new IllegalStateException("Contract's chaincode is empty !!!"); } // 首先生成合约文件 - File jarFile = newJarFile(); + File jarFile = newJarFile(contractPath); try { FileUtils.writeByteArrayToFile(jarFile, chainCode); // 校验合约文件 - verify(jarFile); + verify(contractPath, jarFile); } catch (Exception e) { throw new IllegalStateException(e); } finally { @@ -132,7 +132,11 @@ public class ContractJarUtils { } } - private static void verify(File jarFile) throws Exception { + public static void verify(byte[] chainCode) { + verify(null, chainCode); + } + + private static void verify(String contractPath, File jarFile) throws Exception { // 首先判断jarFile中是否含有META-INF/JDCHAIN.TXT,并将其读出 URL jarUrl = new URL("jar:file:" + jarFile.getPath() + "!/" + CONTRACT_MF); InputStream inputStream = jarUrl.openStream(); @@ -152,7 +156,7 @@ public class ContractJarUtils { String txt = new String(bytes, StandardCharsets.UTF_8); // 生成新的Jar包文件,该文件路径与JarFile基本一致 - File tempJar = newJarFile(); + File tempJar = newJarFile(contractPath); // 复制除JDCHAIN.TXT之外的部分 copy(jarFile, tempJar, null, null, CONTRACT_MF); @@ -223,7 +227,16 @@ public class ContractJarUtils { } } - private static File newJarFile() { + private static File newJarFile(String contractPath) { + + if (contractPath != null && contractPath.length() > 0) { + return new File(contractPath + File.separator + + "contract-" + + System.currentTimeMillis() + "-" + + System.nanoTime() + "-" + + FILE_RANDOM.nextInt(1024) + + ".jar"); + } return new File("contract-" + System.currentTimeMillis() + "-" + System.nanoTime() + "-" + From 3f97b0c9172a9cced9f9c071d41267c70f00d4ca Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Tue, 22 Oct 2019 10:45:28 +0800 Subject: [PATCH 3/4] =?UTF-8?q?Generate=20jar=20file=20modify=20to=20gener?= =?UTF-8?q?ate=20temporary=20file=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blockchain/contract/ContractJarUtils.java | 68 ++++++++++++------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java index 50643d06..b2a3764b 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java @@ -115,7 +115,7 @@ public class ContractJarUtils { throw new IllegalStateException("Contract's chaincode is empty !!!"); } // 首先生成合约文件 - File jarFile = newJarFile(contractPath); + File jarFile = newJarTempFile(); try { FileUtils.writeByteArrayToFile(jarFile, chainCode); // 校验合约文件 @@ -125,9 +125,9 @@ public class ContractJarUtils { } finally { // 删除文件 try { - FileUtils.forceDelete(jarFile); + jarFile.deleteOnExit(); } catch (Exception e) { - throw new IllegalStateException(e); + // DO NOTHING } } } @@ -144,6 +144,7 @@ public class ContractJarUtils { throw new IllegalStateException(CONTRACT_MF + " IS NULL !!!"); } byte[] bytes; + try { bytes = IOUtils.toByteArray(inputStream); } finally { @@ -156,20 +157,25 @@ public class ContractJarUtils { String txt = new String(bytes, StandardCharsets.UTF_8); // 生成新的Jar包文件,该文件路径与JarFile基本一致 - File tempJar = newJarFile(contractPath); - - // 复制除JDCHAIN.TXT之外的部分 - copy(jarFile, tempJar, null, null, CONTRACT_MF); - - // 生成新Jar包对应的Hash内容 - String verifyTxt = contractMF(FileUtils.readFileToByteArray(tempJar)); + File tempJar = newJarTempFile(); + try { + // 复制除JDCHAIN.TXT之外的部分 + copy(jarFile, tempJar, null, null, CONTRACT_MF); - // 删除临时文件 - FileUtils.forceDelete(tempJar); + // 生成新Jar包对应的Hash内容 + String verifyTxt = contractMF(FileUtils.readFileToByteArray(tempJar)); - // 校验Jar包内容 - if (!txt.equals(verifyTxt)) { - throw new IllegalStateException(String.format("Jar [%s] verify Illegal !!!", jarFile.getName())); + // 校验Jar包内容 + if (!txt.equals(verifyTxt)) { + throw new IllegalStateException(String.format("Jar [%s] verify Illegal !!!", jarFile.getName())); + } + } finally { + try { + // 删除临时文件 + tempJar.deleteOnExit(); + } catch (Exception e) { + // DO NOTHING + } } } @@ -227,20 +233,30 @@ public class ContractJarUtils { } } - private static File newJarFile(String contractPath) { + private static File newJarTempFile() { - if (contractPath != null && contractPath.length() > 0) { - return new File(contractPath + File.separator + - "contract-" + + try { + return File.createTempFile("contract-" + System.currentTimeMillis() + "-" + System.nanoTime() + "-" + - FILE_RANDOM.nextInt(1024) + - ".jar"); + FILE_RANDOM.nextInt(1024), ".jar"); + } catch (Exception e) { + throw new IllegalStateException(e); } - return new File("contract-" + - System.currentTimeMillis() + "-" + - System.nanoTime() + "-" + - FILE_RANDOM.nextInt(1024) + - ".jar"); +// +// if (contractPath != null && contractPath.length() > 0) { +// return new File(contractPath + File.separator + +// "contract-" + +// System.currentTimeMillis() + "-" + +// System.nanoTime() + "-" + +// FILE_RANDOM.nextInt(1024) + +// ".jar"); +// } +// +// return new File("contract-" + +// System.currentTimeMillis() + "-" + +// System.nanoTime() + "-" + +// FILE_RANDOM.nextInt(1024) + +// ".jar"); } } From f2d34f56e8970ac52588443f86e11b5d5faa8302 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Thu, 24 Oct 2019 14:12:34 +0800 Subject: [PATCH 4/4] solve pre compute null pointer bug --- .../bftsmart/service/BftsmartNodeServer.java | 98 ++++++++++++++++--- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java index 48c85f79..c0194d64 100644 --- a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java +++ b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java @@ -359,33 +359,105 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer * Used by consensus write phase, pre compute new block hash * */ +// public BatchAppResultImpl preComputeAppHash(byte[][] commands) { +// String batchId = messageHandle.beginBatch(realmName); +// List> asyncFutureLinkedList = new ArrayList<>(commands.length); +// List responseLinkedList = new ArrayList<>(); +// try { +// int msgId = 0; +// for (byte[] txContent : commands) { +// AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); +// asyncFutureLinkedList.add(asyncFuture); +// } +// StateSnapshot stateSnapshot = messageHandle.completeBatch(realmName, batchId); +// byte[] blockHashBytes = stateSnapshot.getSnapshot(); +// +// for (int i = 0; i< asyncFutureLinkedList.size(); i++) { +// responseLinkedList.add(asyncFutureLinkedList.get(i).get()); +// } +// +// +// return new BatchAppResultImpl(responseLinkedList, blockHashBytes, batchId); +// +// } catch (Exception e) { +// // todo 需要处理应答码 404 +// LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); +// messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_CONSENSUS_PHASE_PRECOMPUTE_ROLLBACK.CODE); +// } +// +// return null; +// } + + /** + * Used by consensus write phase, pre compute new block hash + */ public BatchAppResultImpl preComputeAppHash(byte[][] commands) { String batchId = messageHandle.beginBatch(realmName); List> asyncFutureLinkedList = new ArrayList<>(commands.length); List responseLinkedList = new ArrayList<>(); + BatchAppResultImpl result; try { int msgId = 0; - for (byte[] txContent : commands) { - AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); - asyncFutureLinkedList.add(asyncFuture); - } - StateSnapshot stateSnapshot = messageHandle.completeBatch(realmName, batchId); - byte[] blockHashBytes = stateSnapshot.getSnapshot(); - for (int i = 0; i< asyncFutureLinkedList.size(); i++) { - responseLinkedList.add(asyncFutureLinkedList.get(i).get()); + boolean isOK = true; + + for (int i = 0; i < commands.length; i++) { + + byte[] txContent = commands[i]; + try { + AsyncFuture asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); + asyncFutureLinkedList.add(asyncFuture); + } catch (BlockRollbackException e) { + + LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); + + isOK = false; + + break; + } } + if (isOK) { + StateSnapshot stateSnapshot = messageHandle.completeBatch(realmName, batchId); + byte[] blockHashBytes = stateSnapshot.getSnapshot(); + + for (int i = 0; i < asyncFutureLinkedList.size(); i++) { + responseLinkedList.add(asyncFutureLinkedList.get(i).get()); + } + + result = new BatchAppResultImpl(responseLinkedList, blockHashBytes, batchId); + result.setErrorCode((byte) 0); + + return result; + } else { + + for (int i = 0; i < commands.length; i++) { + responseLinkedList.add(createAppResponse(commands[i])); + } + + Random random = new Random(); + byte[] rand = new byte[4]; + random.nextBytes(rand); - return new BatchAppResultImpl(responseLinkedList, blockHashBytes, batchId); + result = new BatchAppResultImpl(responseLinkedList, rand, batchId); + result.setErrorCode((byte) 1); + + return result; + } } catch (Exception e) { - // todo 需要处理应答码 404 - LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); - messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_CONSENSUS_PHASE_PRECOMPUTE_ROLLBACK.CODE); + LOGGER.error("Error occurred while genearte batch app result! --" + e.getMessage(), e); + throw e; } + } - return null; + public byte[] createAppResponse(byte[] command) { + TransactionRequest txRequest = BinaryProtocol.decode(command); + + TxResponseMessage resp = new TxResponseMessage(txRequest.getTransactionContent().getHash()); + resp.setExecutionState(TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); + + return BinaryProtocol.encode(resp, TransactionResponse.class); } /**