Browse Source

Merge branch 'develop' into feature/latest_record_first_show

tags/1.1.1^2
zhaoguangwei 4 years ago
parent
commit
2671c33ce9
3 changed files with 182 additions and 38 deletions
  1. +85
    -13
      source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java
  2. +38
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java
  3. +59
    -25
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java

+ 85
- 13
source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java View File

@@ -359,33 +359,105 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer
* Used by consensus write phase, pre compute new block hash * Used by consensus write phase, pre compute new block hash
* *
*/ */
// public BatchAppResultImpl preComputeAppHash(byte[][] commands) {
// String batchId = messageHandle.beginBatch(realmName);
// List<AsyncFuture<byte[]>> asyncFutureLinkedList = new ArrayList<>(commands.length);
// List<byte[]> responseLinkedList = new ArrayList<>();
// try {
// int msgId = 0;
// for (byte[] txContent : commands) {
// AsyncFuture<byte[]> 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) { public BatchAppResultImpl preComputeAppHash(byte[][] commands) {
String batchId = messageHandle.beginBatch(realmName); String batchId = messageHandle.beginBatch(realmName);
List<AsyncFuture<byte[]>> asyncFutureLinkedList = new ArrayList<>(commands.length); List<AsyncFuture<byte[]>> asyncFutureLinkedList = new ArrayList<>(commands.length);
List<byte[]> responseLinkedList = new ArrayList<>(); List<byte[]> responseLinkedList = new ArrayList<>();
BatchAppResultImpl result;
try { try {
int msgId = 0; int msgId = 0;
for (byte[] txContent : commands) {
AsyncFuture<byte[]> 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<byte[]> 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) { } 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);
} }


/** /**


+ 38
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java View File

@@ -5,15 +5,26 @@ import com.jd.blockchain.gateway.PeerService;
import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionRequest;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.net.URL;


@Service @Service
public class GatewayInterceptServiceHandler implements GatewayInterceptService { public class GatewayInterceptServiceHandler implements GatewayInterceptService {


private static String contractsPath;

@Autowired @Autowired
private PeerService peerService; private PeerService peerService;


static {
contractsPath = jarRootDir();
}

@Override @Override
public void intercept(TransactionRequest txRequest) { public void intercept(TransactionRequest txRequest) {
// 当前仅处理合约发布的请求 // 当前仅处理合约发布的请求
@@ -29,7 +40,34 @@ public class GatewayInterceptServiceHandler implements GatewayInterceptService {
} }


private void contractCheck(final ContractCodeDeployOperation contractOP) { private void contractCheck(final ContractCodeDeployOperation contractOP) {

// 校验chainCode // 校验chainCode
ContractJarUtils.verify(contractOP.getChainCode()); 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);
}
}
} }

+ 59
- 25
source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractJarUtils.java View File

@@ -110,36 +110,46 @@ public class ContractJarUtils {
return dotClassName; return dotClassName;
} }


public static void verify(byte[] chainCode) {
public static void verify(String contractPath, byte[] chainCode) {
if (chainCode == null || chainCode.length == 0) { if (chainCode == null || chainCode.length == 0) {
throw new IllegalStateException("Contract's chaincode is empty !!!"); throw new IllegalStateException("Contract's chaincode is empty !!!");
} }
// 首先生成合约文件 // 首先生成合约文件
File jarFile = newJarFile();
File jarFile = newJarTempFile();
try { try {
FileUtils.writeByteArrayToFile(jarFile, chainCode); FileUtils.writeByteArrayToFile(jarFile, chainCode);
// 校验合约文件 // 校验合约文件
verify(jarFile);
verify(contractPath, jarFile);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} finally { } finally {
// 删除文件 // 删除文件
try { try {
FileUtils.forceDelete(jarFile);
jarFile.deleteOnExit();
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException(e);
// DO NOTHING
} }
} }
} }


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,并将其读出 // 首先判断jarFile中是否含有META-INF/JDCHAIN.TXT,并将其读出
URL jarUrl = new URL("jar:file:" + jarFile.getPath() + "!/" + CONTRACT_MF); URL jarUrl = new URL("jar:file:" + jarFile.getPath() + "!/" + CONTRACT_MF);
InputStream inputStream = jarUrl.openStream(); InputStream inputStream = jarUrl.openStream();
if (inputStream == null) { if (inputStream == null) {
throw new IllegalStateException(CONTRACT_MF + " IS 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) { if (bytes == null || bytes.length == 0) {
throw new IllegalStateException(CONTRACT_MF + " IS Illegal !!!"); throw new IllegalStateException(CONTRACT_MF + " IS Illegal !!!");
} }
@@ -147,20 +157,25 @@ public class ContractJarUtils {
String txt = new String(bytes, StandardCharsets.UTF_8); String txt = new String(bytes, StandardCharsets.UTF_8);


// 生成新的Jar包文件,该文件路径与JarFile基本一致 // 生成新的Jar包文件,该文件路径与JarFile基本一致
File tempJar = newJarFile();

// 复制除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
}
} }
} }


@@ -218,11 +233,30 @@ public class ContractJarUtils {
} }
} }


private static File newJarFile() {
return new File("contract-" +
System.currentTimeMillis() + "-" +
System.nanoTime() + "-" +
FILE_RANDOM.nextInt(1024) +
".jar");
private static File newJarTempFile() {

try {
return File.createTempFile("contract-" +
System.currentTimeMillis() + "-" +
System.nanoTime() + "-" +
FILE_RANDOM.nextInt(1024), ".jar");
} catch (Exception e) {
throw new IllegalStateException(e);
}
//
// 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");
} }
} }

Loading…
Cancel
Save