Browse Source

Merge remote-tracking branch 'origin/develop' into feature/admin1-local

# Conflicts:
#	source/deployment/deployment-peer/src/main/resources/scripts/startup.sh
#	source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
tags/1.1.0
shaozhuguang 5 years ago
parent
commit
a44e6f7743
100 changed files with 4720 additions and 1997 deletions
  1. +0
    -11
      .travis.yml
  2. +0
    -2
      README.md
  3. +2
    -3
      source/base/pom.xml
  4. +54
    -11
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  5. +19
    -0
      source/base/src/main/java/com/jd/blockchain/consts/Global.java
  6. +7
    -0
      source/binary-proto/pom.xml
  7. +81
    -0
      source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/BftsmartConsensusSettingsBuilder.java
  8. +2
    -0
      source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java
  9. +4
    -0
      source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusSettingsBuilder.java
  10. +49
    -2
      source/consensus/consensus-mq/src/main/java/com/jd/blockchain/consensus/mq/MsgQueueConsensusSettingsBuilder.java
  11. +25
    -0
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/InstantiatedContractCode.java
  12. +274
    -0
      source/contract/contract-maven-plugin/ReadME.MD
  13. +11
    -66
      source/contract/contract-maven-plugin/pom.xml
  14. +0
    -127
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
  15. +0
    -221
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java
  16. +7
    -22
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployExeUtil.java
  17. +3
    -3
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java
  18. +98
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/AbstractContract.java
  19. +66
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractClass.java
  20. +288
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractCompileMojo.java
  21. +9
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractConstant.java
  22. +43
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractField.java
  23. +81
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractMethod.java
  24. +22
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/asm/ASMClassVisitor.java
  25. +108
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/asm/ASMMethodVisitor.java
  26. +155
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/BlackList.java
  27. +93
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/DependencyExclude.java
  28. +30
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/WhiteList.java
  29. +169
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/ResolveEngine.java
  30. +224
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/VerifyEngine.java
  31. +19
    -0
      source/contract/contract-maven-plugin/src/main/resources/blacks.conf
  32. +0
    -1
      source/contract/contract-maven-plugin/src/main/resources/config.properties
  33. +22
    -0
      source/contract/contract-maven-plugin/src/main/resources/providers.conf
  34. +0
    -19
      source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties
  35. +3
    -0
      source/contract/contract-maven-plugin/src/main/resources/whites.conf
  36. +0
    -28
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java
  37. +21
    -21
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java
  38. +50
    -0
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractTestBase.java
  39. +28
    -0
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java
  40. +47
    -0
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest_.java
  41. +67
    -67
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/MyProjectStub.java
  42. BIN
      source/contract/contract-maven-plugin/src/test/resources/complex.jar
  43. +8
    -2
      source/contract/contract-samples/pom.xml
  44. +7
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java
  45. +12
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java
  46. +6
    -6
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/ECDSAUtils.java
  47. +187
    -0
      source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/KeyGenUtils.java
  48. +62
    -13
      source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CSRBuilder.java
  49. +16
    -0
      source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CertParser.java
  50. +145
    -0
      source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunctionTest.java
  51. +186
    -0
      source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunctionTest.java
  52. +80
    -0
      source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunctionTest.java
  53. +8
    -4
      source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CertParserTest.java
  54. +6
    -13
      source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java
  55. +0
    -0
      source/deployment/deployment-gateway/conf/application-gw.properties
  56. +6
    -4
      source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java
  57. +2
    -2
      source/deployment/deployment-peer/pom.xml
  58. +2
    -2
      source/deployment/deployment-peer/src/main/resources/assembly.xml
  59. +1
    -1
      source/deployment/deployment-peer/src/main/resources/scripts/startup.sh
  60. +1
    -19
      source/gateway/pom.xml
  61. +7
    -7
      source/gateway/src/main/java/com/jd/blockchain/gateway/GatewayServerBooter.java
  62. +8
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptService.java
  63. +35
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java
  64. +0
    -1
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java
  65. +13
    -12
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
  66. +551
    -549
      source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
  67. +1
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java
  68. +7
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/web/TxProcessingController.java
  69. +5
    -0
      source/ledger/ledger-core/pom.xml
  70. +0
    -26
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountPrivilege.java
  71. +5
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java
  72. +0
    -168
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AuthorizableDataSet.java
  73. +0
    -40
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Authorization.java
  74. +0
    -42
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AuthorizationVO.java
  75. +4
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/BaseAccount.java
  76. +0
    -21
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Consensus.java
  77. +2
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
  78. +29
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountQuery.java
  79. +11
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java
  80. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/CryptoConfig.java
  81. +95
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
  82. +32
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountQuery.java
  83. +10
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java
  84. +122
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DefaultOperationHandleRegisteration.java
  85. +209
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyLedgerDataset.java
  86. +98
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/FullPermissionedSecurityManager.java
  87. +0
    -22
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Gateway.java
  88. +1
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenesisLedgerStorageProxy.java
  89. +0
    -356
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminAccount.java
  90. +12
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataQuery.java
  91. +481
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java
  92. +0
    -5
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminPrivilege.java
  93. +0
    -16
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdministration.java
  94. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerBlockData.java
  95. +3
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerConfiguration.java
  96. +19
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataQuery.java
  97. +0
    -21
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataSet.java
  98. +22
    -17
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataset.java
  99. +18
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java
  100. +2
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerInitProposal.java

+ 0
- 11
.travis.yml View File

@@ -1,11 +0,0 @@
language: java
jdk:
- openjdk8

before_install:
- cd ./tools
- mvn install:install-file -Dfile=core-0.1.4.jar -DgroupId=com.yahoo.ycsb -DartifactId=core -Dversion=0.1.4 -Dpackaging=jar -DgeneratePom=true -DcreateChecksum=true
- cd ../source

script:
- mvn clean package

+ 0
- 2
README.md View File

@@ -3,8 +3,6 @@


[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.jd.blockchain/sdk-pack/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.jd.blockchain/sdk-pack/)
[![Build Status](https://travis-ci.com/blockchain-jd-com/jdchain.svg?branch=master)](https://travis-ci.org/blockchain-jd-com/jdchain)


------------------------------------------------------------------------


+ 2
- 3
source/base/pom.xml View File

@@ -11,9 +11,8 @@

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

</dependencies>
</project>

+ 54
- 11
source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java View File

@@ -8,11 +8,11 @@ package com.jd.blockchain.consts;
*/
public interface DataCodes {

public static final int BYTES_VALUE = 0x80;
public static final int BYTES_VALUE_LIST = 0x81;
public static final int BYTES_VALUE = 0x080;
public static final int BYTES_VALUE_LIST = 0x081;

public static final int BLOCK_CHAIN_IDENTITY = 0x90;
public static final int BLOCK_CHAIN_IDENTITY = 0x090;

public static final int BLOCK = 0x100;

@@ -22,6 +22,8 @@ public interface DataCodes {

public static final int DATA_SNAPSHOT = 0x130;

// public static final int LEDGER_ADMIN_DATA = 0x131;

public static final int TX = 0x200;

public static final int TX_LEDGER = 0x201;
@@ -49,15 +51,43 @@ public interface DataCodes {

public static final int TX_OP_CONTRACT_EVENT_SEND = 0x340;

public static final int TX_RESPONSE = 0x350;
public static final int TX_OP_PARTICIPANT_REG = 0x350;
public static final int TX_OP_PARTICIPANT_STATE_UPDATE = 0x351;

public static final int TX_RESPONSE = 0x360;

public static final int TX_OP_RESULT = 0x370;
public static final int TX_OP_ROLE_CONFIGURE = 0x371;
public static final int TX_OP_ROLE_CONFIGURE_ENTRY = 0x372;
public static final int TX_OP_USER_ROLES_AUTHORIZE = 0x373;
public static final int TX_OP_USER_ROLE_AUTHORIZE_ENTRY = 0x374;

// enum types of permissions;
public static final int ENUM_TX_PERMISSION = 0x401;
public static final int ENUM_LEDGER_PERMISSION = 0x402;
public static final int ENUM_MULTI_ROLES_POLICY = 0x403;

public static final int TX_OP_RESULT = 0x360;
public static final int PRIVILEGE_SET = 0x410;

public static final int ROLE_SET = 0x411;
public static final int SECURITY_INIT_SETTING = 0x420;

public static final int SECURITY_ROLE_INIT_SETTING = 0x421;
public static final int SECURITY_USER_AUTH_INIT_SETTING = 0x422;

// contract types of metadata;
public static final int METADATA = 0x600;
public static final int METADATA_V2 = 0x601;

public static final int METADATA_INIT_SETTING = 0x610;

public static final int METADATA_INIT_PERMISSION = 0x611;
public static final int METADATA_INIT_PROPOSAL = 0x611;

public static final int METADATA_INIT_DECISION = 0x612;

@@ -65,11 +95,22 @@ public interface DataCodes {

public static final int METADATA_CONSENSUS_PARTICIPANT = 0x621;

// public static final int METADATA_CONSENSUS_NODE = 0x630;
//
// public static final int METADATA_CONSENSUS_SETTING = 0x631;
//
// public static final int METADATA_PARTICIPANT_INFO = 0x640;
//
// public static final int METADATA_CRYPTO_SETTING = 0x642;


// public static final int METADATA_CONSENSUS_NODE = 0x630;

public static final int METADATA_CONSENSUS_SETTING = 0x631;

// public static final int METADATA_PARTICIPANT_INFO = 0x640;
public static final int METADATA_PARTICIPANT_INFO = 0x640;

public static final int METADATA_PARTICIPANT_STATE_INFO = 0x641;

public static final int METADATA_CRYPTO_SETTING = 0x642;
@@ -83,11 +124,10 @@ public interface DataCodes {

public static final int DATA = 0x900;

//contract related;
// contract related;
public static final int CONTRACT = 0xA00;


//...0xA19
// ...0xA19
public static final int HASH = 0xB00;

public static final int HASH_OBJECT = 0xB10;
@@ -100,6 +140,8 @@ public interface DataCodes {

public static final int ENUM_TYPE_BYTES_VALUE_TYPE = 0xB23;

public static final int ENUM_TYPE_PARTICIPANT_NODE_STATE = 0xB24;

public static final int DIGITALSIGNATURE = 0xB30;

public static final int DIGITALSIGNATURE_BODY = 0xB31;
@@ -152,4 +194,5 @@ public interface DataCodes {

public static final int CONSENSUS_MSGQUEUE_BLOCK_SETTINGS = CONSENSUS_MSGQUEUE | 0x05;

}

+ 19
- 0
source/base/src/main/java/com/jd/blockchain/consts/Global.java View File

@@ -0,0 +1,19 @@
package com.jd.blockchain.consts;

import java.util.TimeZone;

public class Global {
public static final String DEFAULT_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSZ";
public static final String DEFAULT_TIME_ZONE = "GMT+08:00";
static {
initialize();
}
public static void initialize() {
TimeZone.setDefault(TimeZone.getTimeZone(DEFAULT_TIME_ZONE));
}
}

+ 7
- 0
source/binary-proto/pom.xml View File

@@ -15,9 +15,16 @@
<artifactId>utils-common</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 81
- 0
source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/BftsmartConsensusSettingsBuilder.java View File

@@ -2,11 +2,18 @@ package com.jd.blockchain.consensus.bftsmart;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.NodeSettings;
import com.jd.blockchain.ledger.ParticipantInfo;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.PropertiesUtils;
import com.jd.blockchain.utils.Property;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.BytesUtils;
import com.jd.blockchain.utils.net.NetworkAddress;
@@ -64,6 +71,8 @@ public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilde
*/
public static final String CONSENSUS_SECURE_PATTERN = "system.server.%s.network.secure";

public static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider";



private static Properties CONFIG_TEMPLATE;
@@ -164,6 +173,30 @@ public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilde
return config;
}

@Override
public Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo) {

//update consensus setting through node and system config two aspects
BftsmartConsensusSettings consensusSettings = (BftsmartConsensusSettings) ConsensusProviders.getProvider(BFTSMART_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder().decode(oldConsensusSettings.toBytes());

Property[] systemConfigs = systemConfigs(consensusSettings.getSystemConfigs());

BftsmartNodeSettings[] nodeSettings = nodeSettings(consensusSettings.getNodes(), participantInfo);

BftsmartConsensusConfig bftsmartConsensusConfig = new BftsmartConsensusConfig(nodeSettings, systemConfigs);

// for(int i = 0 ;i < bftsmartConsensusConfig.getNodes().length; i++) {
// System.out.printf("id = %d, host = %s, port = %d\r\n", bftsmartConsensusConfig.getNodes()[i].getId(), bftsmartConsensusConfig.getNodes()[i].getNetworkAddress().getHost(), bftsmartConsensusConfig.getNodes()[i].getNetworkAddress().getPort());
// }
//
// for(int i = 0 ;i < bftsmartConsensusConfig.getSystemConfigs().length; i++) {
// System.out.printf("property name = %s, property value = %s\r\n",bftsmartConsensusConfig.getSystemConfigs()[i].getName(), bftsmartConsensusConfig.getSystemConfigs()[i].getValue());
// }

return new Bytes(ConsensusProviders.getProvider(BFTSMART_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder().encode(bftsmartConsensusConfig));

}

private static String keyOfNode(String pattern, int id) {
return String.format(pattern, id);
}
@@ -224,4 +257,52 @@ public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilde
PropertiesUtils.setValues(props, bftsmartSettings.getSystemConfigs());
}

/**
*
* update system.servers.num property
*
*/
private Property[] systemConfigs(Property[] systemConfigs) {
Map<String, Property> propertyMap = convert2Map(systemConfigs);
int serverNum = Integer.parseInt(propertyMap.get("system.servers.num").getValue());
propertyMap.put("system.servers.num", new Property("system.servers.num", String.valueOf(serverNum + 1)));
return convert2Array(propertyMap);

}

private Map<String, Property> convert2Map(Property[] properties) {
Map<String, Property> propertyMap = new HashMap<>();
for (Property property : properties) {
propertyMap.put(property.getName(), property);
}
return propertyMap;
}

private Property[] convert2Array(Map<String, Property> map) {
Property[] properties = new Property[map.size()];
int index = 0;
for (Map.Entry<String, Property> entry : map.entrySet()) {
properties[index++] = entry.getValue();
}
return properties;
}

/**
*
* update node setting
*
*/
private BftsmartNodeSettings[] nodeSettings(NodeSettings[] nodeSettings, ParticipantInfo participantInfo) {

BftsmartNodeConfig bftsmartNodeConfig = new BftsmartNodeConfig(participantInfo.getPubKey(), nodeSettings.length, participantInfo.getNetworkAddress());

BftsmartNodeSettings[] bftsmartNodeSettings = new BftsmartNodeSettings[nodeSettings.length + 1];
for (int i = 0; i < nodeSettings.length; i++) {
bftsmartNodeSettings[i] = (BftsmartNodeSettings)nodeSettings[i];
}
bftsmartNodeSettings[nodeSettings.length] = bftsmartNodeConfig;
return bftsmartNodeSettings;
}


}

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

@@ -52,11 +52,13 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer

private BftsmartConsensusManageService manageService;


private volatile BftsmartTopology topology;

private volatile BftsmartConsensusSettings setting;

private TOMConfiguration tomConfig;

private TOMConfiguration outerTomConfig;

private HostsConfig hostsConfig;


+ 4
- 0
source/consensus/consensus-framework/src/main/java/com/jd/blockchain/consensus/ConsensusSettingsBuilder.java View File

@@ -1,6 +1,8 @@
package com.jd.blockchain.consensus;

import com.jd.blockchain.ledger.ParticipantInfo;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.utils.Bytes;

import java.util.Properties;

@@ -16,6 +18,8 @@ public interface ConsensusSettingsBuilder {
* @return
*/
ConsensusSettings createSettings(Properties props, ParticipantNode[] participantNodes);

Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo);
Properties createPropertiesTemplate();



+ 49
- 2
source/consensus/consensus-mq/src/main/java/com/jd/blockchain/consensus/mq/MsgQueueConsensusSettingsBuilder.java View File

@@ -8,6 +8,7 @@
*/
package com.jd.blockchain.consensus.mq;

import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.consensus.ConsensusSettingsBuilder;
import com.jd.blockchain.consensus.NodeSettings;
@@ -20,12 +21,14 @@ import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings;
import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings;
import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.KeyGenUtils;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.ParticipantInfo;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.PropertiesUtils;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.BytesEncoder;
import com.jd.blockchain.utils.io.BytesUtils;
import com.jd.blockchain.utils.io.FileUtils;
import com.jd.blockchain.utils.net.NetworkAddress;
@@ -82,6 +85,8 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde

public static final String MSG_QUEUE_BLOCK_MAXDELAY = "system.msg.queue.block.maxdelay";

public static final String MSG_QUEUE_PROVIDER = "com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider";

private static Properties CONFIG_TEMPLATE;

static {
@@ -129,7 +134,7 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde
String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id);

String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey);
PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey);
PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey);

// PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey));
resolvingProps.remove(keyOfPubkey);
@@ -145,6 +150,48 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde
return consensusConfig;
}

private MsgQueueNodeSettings[] nodeSettings(NodeSettings[] nodeSettings, ParticipantInfo participantInfo) {

MsgQueueNodeSettings msgQueueNodeSettings = new MsgQueueNodeConfig();
((MsgQueueNodeConfig) msgQueueNodeSettings).setAddress(AddressEncoding.generateAddress(participantInfo.getPubKey()).toBase58());
((MsgQueueNodeConfig) msgQueueNodeSettings).setPubKey(participantInfo.getPubKey());

MsgQueueNodeSettings[] msgQueuetNodeSettings = new MsgQueueNodeSettings[nodeSettings.length + 1];
for (int i = 0; i < nodeSettings.length; i++) {
msgQueuetNodeSettings[i] = (MsgQueueNodeSettings)nodeSettings[i];
}
msgQueuetNodeSettings[nodeSettings.length] = msgQueueNodeSettings;

return msgQueuetNodeSettings;
}

@Override
public Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo) {

BytesEncoder<ConsensusSettings> consensusEncoder = ConsensusProviders.getProvider(MSG_QUEUE_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder();

MsgQueueConsensusSettings consensusSettings = (MsgQueueConsensusSettings) consensusEncoder.decode(oldConsensusSettings.toBytes());

MsgQueueNodeSettings[] nodeSettings = nodeSettings(consensusSettings.getNodes(), participantInfo);

MsgQueueConsensusConfig msgQueueConsensusConfig = new MsgQueueConsensusConfig();
for (int i = 0; i < nodeSettings.length; i++) {
msgQueueConsensusConfig.addNodeSettings(nodeSettings[i]);
}

msgQueueConsensusConfig.setBlockSettings(consensusSettings.getBlockSettings());

msgQueueConsensusConfig.setNetworkSettings(consensusSettings.getNetworkSettings());


// for(int i = 0 ;i < msgQueueConsensusConfig.getNodes().length; i++) {
// System.out.printf("node addr = %s\r\n", msgQueueConsensusConfig.getNodes()[i].getAddress());
// }

return new Bytes(consensusEncoder.encode(msgQueueConsensusConfig));

}

@Override
public Properties createPropertiesTemplate() {
return PropertiesUtils.cloneFrom(CONFIG_TEMPLATE);


+ 25
- 0
source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/InstantiatedContractCode.java View File

@@ -0,0 +1,25 @@
package com.jd.blockchain.contract.jvm;

import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.utils.Bytes;

public class InstantiatedContractCode<T> extends AbstractContractCode {

private T instance;

public InstantiatedContractCode(Bytes address, long version, Class<T> delaredInterface, T instance) {
super(address, version, resolveContractDefinition(delaredInterface, instance.getClass()));
this.instance = instance;
}

private static ContractDefinition resolveContractDefinition(Class<?> declaredIntf, Class<?> implementedClass) {
ContractType contractType = ContractType.resolve(declaredIntf);
return new ContractDefinition(contractType, implementedClass);
}

@Override
protected T getContractInstance() {
return instance;
}

}

+ 274
- 0
source/contract/contract-maven-plugin/ReadME.MD View File

@@ -0,0 +1,274 @@
# 合约编译插件使用教程

### 1、maven引入

在pom.xml文件中引入合约编译插件:
```xml
<plugin>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-maven-plugin</artifactId>
<version>1.0.0.RELEASE</version>
<executions>
<execution>
<id>make-contract</id>
<phase>package</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>com.jd.chain.contracts.ContractTestInfImpl</mainClass>
</manifest>
</archive>
<finalName>contract</finalName>
</configuration>
</plugin>

```

需要说明的几点如下:
+ 1)version:请根据实际JDChain发布版本确认,不同版本会有区别;
+ 2)executions->execution->id:该值请随意指定;
+ 3)executions->execution->phase:建议使用package及其后续阶段(若不了解phase含义,请自行查阅相关信息);
+ 4)executions->execution->goals->goal:必须使用compile;
+ 5)mainClass:必填,该类为需要发布的合约执行类(注意此处是类,不是接口),必须正确配置;
+ 6)finalName:必填,最终在编译正常的情况下,会产生{finalName}-jdchain-contract.jar文件,只有该文件是可以发布到JDChain的合约包;


### 2、执行命令
使用mvn执行命令,下面两种方式均可:

方式一:只执行contract插件命令
```shell
mvn clean compile contract:compile
```

方式二:直接执行打包命令:
```shell
mvn clean package
```


### 3、合约编写要求
合约的执行结果会对整条链产生比较深刻的影响,为了使用户能够更好、更合理的使用合约,目前JDChain约定合约编写规则包括以下几点:

(违反其中任何一点都可能导致合约编译失败,但即使合约编译通过也不能保证合约可百分百运行正常)

+ 1)合约工程必须引入com.jd.blockchain:sdk-pack:该包中有合约正常编写需要使用的基本类;
+ 2)com.jd.blockchain:sdk-pack的scope必须定义为provided;
+ 3)合约发布必须通过合约编译插件进行打包:合约编译插件不但会对Jar包进行校验,同时也会加入JDChain独有的特征,只有具有该特征的Jar才能正常发布;
+ 4)合约中严禁使用随机数、IO、NIO等操作;
+ 5)合约打包时,请使用<scope>provided</scope>排除常用的工具包,例如FastJson、apache下的一些工具包等;
+ 6)合约必须有一个接口和该接口的实现类,详细要求如下:
- a. 接口必须有@Contract注解;
- b. 接口的可调用方法上必须有@ContractEvent注解,且每个注解中的name属性不能重复;
- c. 合约方法支持入参和返回值,其主要包括所有基本类型;



### 4、合约案例

#### 4.1、代码实例
以下是一个可创建银行账户,指定具体金额,并可以转账的合约代码(逻辑较简单,仅供参考):

合约接口代码如下:
```java
package com.jd.chain.contract;


@Contract
public interface TransferContract {

@ContractEvent(name = "create")
String create(String address, String account, long money);

@ContractEvent(name = "transfer")
String transfer(String address, String from, String to, long money);

@ContractEvent(name = "read")
long read(String address, String account);

@ContractEvent(name = "readAll")
String readAll(String address, String account);
}

```

合约实现类代码如下:
```java
package com.jd.chain.contract;

import com.alibaba.fastjson.JSON;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.KVDataVO;
import com.jd.blockchain.ledger.KVInfoVO;

public class TransferContractImpl implements EventProcessingAware, TransferContract {

private ContractEventContext eventContext;

private HashDigest ledgerHash;

@Override
public String create(String address, String account, long money) {
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
// 肯定有返回值,但若不存在则返回version=-1
if (kvDataEntries != null && kvDataEntries.length > 0) {
long currVersion = kvDataEntries[0].getVersion();
if (currVersion > -1) {
throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account));
}
eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L);
} else {
throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58()));
}
return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n",
address, account, money);
}

@Override
public String transfer(String address, String from, String to, long money) {
// 首先查询余额
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to);
if (kvDataEntries == null || kvDataEntries.length != 2) {
throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to));
} else {
// 判断from账号中钱数量是否足够
long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L;
for (KVDataEntry kvDataEntry : kvDataEntries) {
if (kvDataEntry.getKey().equals(from)) {
fromMoney = (long) kvDataEntry.getValue();
fromVersion = kvDataEntry.getVersion();
} else {
toMoney = (long) kvDataEntry.getValue();
toVersion = kvDataEntry.getVersion();
}
}
if (fromMoney < money) {
throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from));
}
long fromNewMoney = fromMoney - money;
long toNewMoney = toMoney + money;
// 重新设置
eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion);
eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion);
}

return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money);
}

@Override
public long read(String address, String account) {
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
if (kvDataEntries == null || kvDataEntries.length == 0) {
return -1;
}
return (long)kvDataEntries[0].getValue();
}

@Override
public String readAll(String address, String account) {
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
// 获取最新的版本号
if (kvDataEntries == null || kvDataEntries.length == 0) {
return "";
}
long newestVersion = kvDataEntries[0].getVersion();
if (newestVersion == -1) {
return "";
}
KVDataVO[] kvDataVOS = new KVDataVO[1];
long[] versions = new long[(int)newestVersion + 1];
for (int i = 0; i < versions.length; i++) {
versions[i] = i;
}
KVDataVO kvDataVO = new KVDataVO(account, versions);

kvDataVOS[0] = kvDataVO;

KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS);

KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO);

return JSON.toJSONString(allEntries);
}

@Override
public void beforeEvent(ContractEventContext eventContext) {
this.eventContext = eventContext;
this.ledgerHash = eventContext.getCurrentLedgerHash();
}

@Override
public void postEvent(ContractEventContext eventContext, Exception error) {

}
}
```


#### 4.2、pom.xml文件实例

```xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>com.jd.chain</groupId>
<version>1.0.0.RELEASE</version>
<modelVersion>4.0.0</modelVersion>

<artifactId>contract-samples</artifactId>

<name>contract-samples</name>

<dependencies>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>sdk-pack</artifactId>
<version>1.0.0.RELEASE</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.32</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-maven-plugin</artifactId>
<version>1.0.0.RELEASE</version>
<executions>
<execution>
<id>make-contract</id>
<phase>package</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>com.jd.chain.contract.TransferContractImpl</mainClass>
</manifest>
</archive>
<finalName>contract</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>

```

+ 11
- 66
source/contract/contract-maven-plugin/pom.xml View File

@@ -10,10 +10,6 @@
<artifactId>contract-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>

<properties>
<maven.version>3.3.9</maven.version>
</properties>

<dependencies>
<dependency>
<groupId>com.jd.blockchain</groupId>
@@ -39,59 +35,29 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>${javaparser.version}</version>
</dependency>

<!-- new -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.3.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.3.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.3.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
<scope>test</scope>
<version>3.3.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.maven.plugin-tools/maven-plugin-annotations -->
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>3.0.1</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
</dependency>

<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.4</version>
</dependency>

</dependencies>
@@ -103,27 +69,6 @@
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5</version>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<optimize>false</optimize>
<debug>true</debug>
<showDeprecation>false</showDeprecation>
<showWarnings>false</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</plugins>
</build>
</project>

+ 0
- 127
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java View File

@@ -1,127 +0,0 @@
package com.jd.blockchain;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.utils.IllegalDataException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
* first step, we want to parse the source code by javaParse. But it's repeated and difficult to parse the source.
* This is a try of "from Initail to Abandoned".
* Since we are good at the class, why not?
* Now we change a way of thinking, first we pre-compile the source code, then parse the *.jar.
*
* by zhaogw
* date 2019-06-05 16:17
*/
@Mojo(name = "checkImports")
public class CheckImportsMojo extends AbstractMojo {
Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class);

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

/**
* jar's name;
*/
@Parameter
private String finalName;

@Override
public void execute() throws MojoFailureException {
List<Path> sources;
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties");
Properties properties = new Properties();
properties.load(inputStream);
String[] packageBlackList = properties.getProperty("blacklist").split(",");
Path baseDirPath = project.getBasedir().toPath();
sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList());
for (Path path : sources) {
CompilationUnit compilationUnit = JavaParser.parse(path);

compilationUnit.accept(new MethodVisitor(), null);

NodeList<ImportDeclaration> imports = compilationUnit.getImports();
for (ImportDeclaration imp : imports) {
String importName = imp.getName().asString();
for (String item : packageBlackList) {
if (importName.startsWith(item)) {
throw new MojoFailureException("在源码中不允许包含此引入包:" + importName);
}
}
}

//now we parse the jar;
String jarPath = project.getBuild().getDirectory()+ File.separator+finalName+".jar";
File jarFile = new File(jarPath);
URL jarURL = jarFile.toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL},this.getClass().getClassLoader());
Attributes m = new JarFile(jarFile).getManifest().getMainAttributes();
String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS);
try {
Class mainClass = classLoader.loadClass(contractMainClass);
ContractType.resolve(mainClass);
} catch (ClassNotFoundException e) {
throw new IllegalDataException(e.getMessage());
}
}
} catch (IOException exception) {
logger.error(exception.getMessage());
throw new MojoFailureException("IO ERROR");
} catch (NullPointerException e) {
logger.error(e.getMessage());
}
}

private class MethodVisitor extends VoidVisitorAdapter<Void> {
@Override
public void visit(MethodDeclaration n, Void arg) {
/* here you can access the attributes of the method.
this method will be called for all methods in this
CompilationUnit, including inner class methods */
logger.info("method:"+n.getName());
super.visit(n, arg);
}

@Override
public void visit(ClassOrInterfaceDeclaration n, Void arg) {
logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes());

super.visit(n, arg);
}

@Override
public void visit(PackageDeclaration n, Void arg) {
logger.info("package:"+n.getName());
super.visit(n, arg);
}

}
}

+ 0
- 221
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java View File

@@ -1,221 +0,0 @@
package com.jd.blockchain;

import com.jd.blockchain.utils.ConsoleUtils;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.invoker.*;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


@Mojo(name = "contractCheck")
public class ContractCheckMojo extends AbstractMojo {
Logger logger = LoggerFactory.getLogger(ContractCheckMojo.class);

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

/**
* jar's name;
*/
@Parameter
private String finalName;


/**
* mainClass;
*/
@Parameter
private String mainClass;
/**
* ledgerVersion;
*/
@Parameter
private String ledgerVersion;

/**
* mvnHome;
*/
@Parameter
private String mvnHome;

/**
* first compile the class, then parse it;
*/
@Override
public void execute() {
this.compileFiles();

}

private void compileFiles(){
// 获取当前项目pom.xml文件所在路径
// URL targetClasses = this.getClass().getClassLoader().getResource("");
// File file = new File(targetClasses.getPath());
// String pomXmlPath = file.getParentFile().getParent() + File.separator + "pom.xml";

FileInputStream fis = null;
try {
// fis = new FileInputStream(new File(pomXmlPath));
fis = new FileInputStream(project.getFile());
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(fis);

//delete this plugin(contractCheck) from destination pom.xml;then add the proper plugins;
Plugin plugin = model.getBuild().getPluginsAsMap().get("com.jd.blockchain:contract-maven-plugin");
if(plugin == null){
plugin = model.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:contract-maven-plugin");
}

if(plugin == null) {
return;
}

model.getBuild().removePlugin(plugin);
// model.getBuild().setPlugins(null);

// ConsoleUtils.info("----- 不携带Plugin -----");
// print(model);

List<Plugin> plugins = new ArrayList<>();
plugins.add(createAssembly());
plugins.add(createCheckImports());

model.getBuild().setPlugins(plugins);

ConsoleUtils.info("----- add Plugin -----");
handle(model);

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

private void invokeCompile(File file) {
InvocationRequest request = new DefaultInvocationRequest();

Invoker invoker = new DefaultInvoker();
try {
request.setPomFile(file);

request.setGoals( Collections.singletonList( "verify" ) );
// request.setMavenOpts("-DmainClass="+mainClass);
invoker.setMavenHome(new File(mvnHome));
invoker.execute(request);
} catch (MavenInvocationException e) {
e.printStackTrace();
}
}

private Plugin createCheckImports() {
Plugin plugin = new Plugin();
plugin.setGroupId("com.jd.blockchain");
plugin.setArtifactId("contract-maven-plugin");
plugin.setVersion(ledgerVersion);

Xpp3Dom finalNameNode = new Xpp3Dom("finalName");
finalNameNode.setValue(finalName);
Xpp3Dom configuration = new Xpp3Dom("configuration");
configuration.addChild(finalNameNode);
plugin.setConfiguration(configuration);

PluginExecution pluginExecution = new PluginExecution();
pluginExecution.setId("make-assembly");
pluginExecution.setPhase("verify");
List <String> goals = new ArrayList<>();
goals.add("checkImports");
pluginExecution.setGoals(goals);
List<PluginExecution> pluginExecutions = new ArrayList<>();
pluginExecutions.add(pluginExecution);
plugin.setExecutions(pluginExecutions);

return plugin;
}

private Plugin createAssembly() {
Plugin plugin = new Plugin();
plugin.setArtifactId("maven-assembly-plugin");

Xpp3Dom configuration = new Xpp3Dom("configuration");

Xpp3Dom mainClassNode = new Xpp3Dom("mainClass");
mainClassNode.setValue(mainClass);

Xpp3Dom manifest = new Xpp3Dom("manifest");
manifest.addChild(mainClassNode);

Xpp3Dom archive = new Xpp3Dom("archive");
archive.addChild(manifest);

Xpp3Dom finalNameNode = new Xpp3Dom("finalName");
finalNameNode.setValue(finalName);

Xpp3Dom appendAssemblyId = new Xpp3Dom("appendAssemblyId");
appendAssemblyId.setValue("false");

Xpp3Dom descriptorRef = new Xpp3Dom("descriptorRef");
descriptorRef.setValue("jar-with-dependencies");
Xpp3Dom descriptorRefs = new Xpp3Dom("descriptorRefs");
descriptorRefs.addChild(descriptorRef);

configuration.addChild(finalNameNode);
configuration.addChild(appendAssemblyId);
configuration.addChild(archive);
configuration.addChild(descriptorRefs);
plugin.setConfiguration(configuration);

PluginExecution pluginExecution = new PluginExecution();
pluginExecution.setId("make-assembly");
pluginExecution.setPhase("package");
List <String> goals = new ArrayList<>();
goals.add("single");
pluginExecution.setGoals(goals);
List<PluginExecution> pluginExecutions = new ArrayList<>();
pluginExecutions.add(pluginExecution);
plugin.setExecutions(pluginExecutions);
return plugin;
}

private void handle(Model model) throws IOException {
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

mavenXpp3Writer.write(outputStream, model);

byte[] buffer = outputStream.toByteArray();

//输出文件
// File fileOutput = new File("fileOut.xml");
// File fileOutput = File.createTempFile("fileOut",".xml");
File fileOutput = new File(project.getBasedir().getPath(),"fileOut.xml");
fileOutput.createNewFile();

ConsoleUtils.info("fileOutput's path="+fileOutput.getPath());
//创建文件输出流对象
FileOutputStream fos = new FileOutputStream(fileOutput);
//将字节数组fileInput中的内容输出到文件fileOut.xml中;
ConsoleUtils.info(new String(buffer));
fos.write(buffer);
invokeCompile(fileOutput);
fos.close();
}
}

+ 7
- 22
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployExeUtil.java View File

@@ -7,29 +7,12 @@ import java.io.InputStream;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.KeyGenUtils;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BlockchainIdentityData;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.EndpointRequest;
import com.jd.blockchain.ledger.NodeRequest;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.net.NetworkAddress;
@@ -47,8 +30,8 @@ public enum ContractDeployExeUtil {
PubKey pub = null;
PrivKey prv = null;
try {
prv = KeyGenCommand.readPrivKey(prvPath, KeyGenCommand.encodePassword(rawPassword));
pub = KeyGenCommand.readPubKey(pubPath);
prv = KeyGenUtils.readPrivKey(prvPath, KeyGenUtils.encodePassword(rawPassword));
pub = KeyGenUtils.readPubKey(pubPath);

} catch (Exception e) {
e.printStackTrace();
@@ -64,7 +47,7 @@ public enum ContractDeployExeUtil {
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate();
pub = contractKeyPair.getPubKey();
}else {
pub = KeyGenCommand.readPubKey(pubPath);
pub = KeyGenUtils.readPubKey(pubPath);
}

} catch (Exception e) {
@@ -111,6 +94,8 @@ public enum ContractDeployExeUtil {
DataContractRegistry.register(ContractEventSendOperation.class);
DataContractRegistry.register(DataAccountRegisterOperation.class);
DataContractRegistry.register(UserRegisterOperation.class);
DataContractRegistry.register(ParticipantRegisterOperation.class);
DataContractRegistry.register(ParticipantStateUpdateOperation.class);
}

public BlockchainService initBcsrv(String host, int port) {


+ 3
- 3
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java View File

@@ -1,10 +1,10 @@
package com.jd.blockchain;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.KeyGenUtils;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.StringUtils;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.FileUtils;
@@ -102,8 +102,8 @@ public class ContractDeployMojo extends AbstractMojo {
byte[] contractBytes = FileUtils.readBytes(contractPath);


PrivKey prv = KeyGenCommand.decodePrivKeyWithRawPassword(prvKey, password);
PubKey pub = KeyGenCommand.decodePubKey(pubKey);
PrivKey prv = KeyGenUtils.decodePrivKeyWithRawPassword(prvKey, password);
PubKey pub = KeyGenUtils.decodePubKey(pubKey);
BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv);
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger));



+ 98
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/AbstractContract.java View File

@@ -0,0 +1,98 @@
package com.jd.blockchain.contract.maven;

import com.jd.blockchain.contract.maven.rule.BlackList;
import com.jd.blockchain.contract.maven.rule.WhiteList;

import java.util.List;

public abstract class AbstractContract {

protected String className;

public String getClassName() {
return className;
}

public String getDotClassName() {
return className.replaceAll("/", ".");
}

protected String format(final String inputFormat) {
String formatResult;

String outputFormat = inputFormat;
if (inputFormat.endsWith(";")) {
outputFormat = inputFormat.substring(0, inputFormat.length() - 1);
}
if (outputFormat.startsWith("[L") && outputFormat.length() > 2) {
// 说明是数组,但不显示
formatResult = outputFormat.substring(2);
} else if (outputFormat.startsWith("[") && outputFormat.length() > 1) {
// 说明是数组
formatResult = outputFormat.substring(1);
} else if (outputFormat.startsWith("L") && outputFormat.length() > 1) {
// 说明是非基础类型
formatResult = outputFormat.substring(1);
} else {
formatResult = outputFormat;
}

return formatResult;
}

public static BlackList initBlack(List<String> blackList) {
BlackList contractBlack = new BlackList();
if (blackList != null && !blackList.isEmpty()) {
for (String black : blackList) {
// 首先判断该black是package还是
String packageName = isPackageAndReturn(black);
if (packageName != null) {
// 说明是包
contractBlack.addBlackPackage(packageName);
} else {
String[] classAndMethod = black.split("-");
if (classAndMethod.length == 1) {
// 说明只有ClassName
contractBlack.addBlack(classAndMethod[0], BlackList.COMMON_METHOD);
} else {
contractBlack.addBlack(classAndMethod[0], classAndMethod[1]);
}
}
}
}

return contractBlack;
}

public static WhiteList initWhite(List<String> whiteList) {
WhiteList contractWhite = new WhiteList();

if (whiteList != null && !whiteList.isEmpty()) {
for (String white : whiteList) {
String packageName = isPackageAndReturn(white);
if (packageName != null) {
// 说明是包
contractWhite.addWhite(packageName);
} else {
contractWhite.addWhite(white);
}
}
}

return contractWhite;
}

/**
* 获取配置的packageName
*
* @param config
* @return
* 假设为包,则返回其包名,否则返回NULL
*/
public static String isPackageAndReturn(String config) {
if (config.endsWith("*")) {
return config.substring(0, config.length() - 2);
}
return null;
}
}

+ 66
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractClass.java View File

@@ -0,0 +1,66 @@
package com.jd.blockchain.contract.maven;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ContractClass extends AbstractContract {

// 若出现同名的方法则进行合并(将两个方法中涉及到的内容合并在一起)
private Map<String, ContractMethod> methods = new ConcurrentHashMap<>();

public ContractClass(String className) {
if (className.contains(".")) {
this.className = className.replaceAll("\\.", "/");
} else {
this.className = className;
}
}

/**
* 返回构造方法
*
* @return
*/
public ContractMethod constructor() {
return methods.get(ContractConstant.METHOD_INIT);
}

/**
* 返回该类的所有变量
*
* @return
*/
public List<ContractField> fields() {

List<ContractField> fields = new ArrayList<>();

// 构造方法
ContractMethod initMethod = constructor();
if (initMethod != null) {
fields.addAll(initMethod.getClassFieldList(className));
}
// CLINIT方法
ContractMethod clInitMethod = methods.get(ContractConstant.METHOD_CLINIT);
if (clInitMethod != null) {
fields.addAll(clInitMethod.getClassFieldList(className));
}
return fields;
}

public synchronized ContractMethod method(String methodName) {
if (methods.containsKey(methodName)) {
return methods.get(methodName);
}
ContractMethod method = new ContractMethod(this.className, methodName);

methods.put(methodName, method);

return method;
}

public Map<String, ContractMethod> getMethods() {
return methods;
}
}

+ 288
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractCompileMojo.java View File

@@ -0,0 +1,288 @@
package com.jd.blockchain.contract.maven;

import com.jd.blockchain.contract.maven.rule.BlackList;
import com.jd.blockchain.contract.maven.rule.WhiteList;
import com.jd.blockchain.contract.maven.rule.DependencyExclude;
import com.jd.blockchain.contract.maven.verify.ResolveEngine;
import com.jd.blockchain.contract.maven.verify.VerifyEngine;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.assembly.mojos.SingleAssemblyMojo;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static com.jd.blockchain.contract.ContractJarUtils.BLACK_CONF;
import static com.jd.blockchain.contract.ContractJarUtils.WHITE_CONF;

@Mojo(name = "compile")
public class ContractCompileMojo extends SingleAssemblyMojo {

public static final String JAR_DEPENDENCE = "jar-with-dependencies";

public static final String SCOPE_PROVIDED = "provided";

public static final String SCOPE_COMPILE = "compile";

private DependencyExclude dependencyExclude = new DependencyExclude();

private static BlackList black;

private static WhiteList white;

static {
init();
}

@Override
public void execute() throws MojoExecutionException, MojoFailureException {
// 首先对MainClass进行校验,要求必须有MainClass
String mainClass = mainClassVerify();

// 排除所有依赖,只打包当前代码
// excludeAllArtifactExclude(super.getProject().getDependencyArtifacts());
// handleArtifactCompile(super.getProject().getDependencyArtifacts());
handleArtifactExclude(super.getProject().getDependencyArtifacts());

// 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});

// 执行打包命令
// 该命令生成的是只含有当前项目的实际代码的Jar包,该Jar包仅用于校验MainClass
super.execute();

// 生成解析引擎
ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass);

// 获取本次生成的Jar文件
File defaultJarFile;
try {
defaultJarFile = rename(getProject(), getFinalName());
// 校验当前MainClass是否满足需求
resolveEngine.verifyCurrentProjectMainClass(defaultJarFile);
// 校验完成后将该Jar删除
// FileUtils.forceDelete(mainClassFile);
} catch (Exception e) {
getLog().error(e);
throw new MojoFailureException(e.getMessage());
}

// // 将JDChain本身之外的代码打包进Jar包,然后编译
// handleArtifactExclude(super.getProject().getDependencyArtifacts());
//
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});
//
// // 生成Jar包(该Jar包中不包含JDChain内部的代码)
// super.execute();
//
// File defaultJarFile;
// try {
// defaultJarFile = rename(getProject(), getFinalName());
// } catch (Exception e) {
// getLog().error(e);
// throw new MojoFailureException(e.getMessage());
// }

// 校验该Jar包
verify(defaultJarFile, mainClass);

File deployJarFile = resolveEngine.verify(defaultJarFile);

// 删除中间产生的临时文件
try {
FileUtils.forceDelete(defaultJarFile);
} catch (Exception e) {
getLog().error(e);
}

getLog().info(String.format("JDChain's Contract compile success, path = %s !", deployJarFile.getPath()));



// // 将JDChain本身代码之外的代码移除(不打包进整个Jar)
// handleArtifactExclude(super.getProject().getDependencyArtifacts());
//
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});
//
// // 执行打包命令
// super.execute();

// // 将本次打包好的文件重新命名,以便于后续重新打包需要
// // 把文件改名,然后重新再生成一个文件
// File dstFile;
// try {
// dstFile = rename(getProject(), getFinalName());
// } catch (IOException e) {
// getLog().error(e);
// throw new MojoFailureException(e.getMessage());
// }
//
// // dstFile理论上应该含有
//
// // 首先校验该类的Jar包中是否包含不符合规范的命名,以及该类的代码中的部分解析
//
// ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass);
//
// // 校验mainClass
// resolveEngine.verifyCurrentProjectMainClass(dstFile);
//
//
//
// File finalJarFile = resolveEngine.verify();
//
// // 将所有的依赖的jar包全部打包进一个包中,以便于进行ASM检查
// handleArtifactCompile(super.getProject().getDependencyArtifacts());
//
// // 然后再打包一次,本次打包完成后,其中的代码包含所有的class(JDK自身的除外)
// super.execute();
//
// File jarFile = new File(jarPath(getProject(), getFinalName()));
//
// // 校验mainClass
// resolveEngine.verifyCurrentProjectMainClass(jarFile);
//
// // 对代码中的一些规则进行校验,主要是校验其是否包含一些不允许使用的类、包、方法等
// verify(jarFile, mainClass);
//
// // 删除中间的一些文件
//// try {
//// FileUtils.forceDelete(dstFile);
//// } catch (IOException e) {
//// throw new MojoFailureException(e.getMessage());
//// }
//
// 若执行到此处没有异常则表明打包成功,打印打包成功消息
// getLog().info(String.format("JDChain's Contract compile success, path = %s !", finalJarFile.getPath()));
}

private String mainClassVerify() throws MojoFailureException {
// 要求必须有MainClass
String mainClass;
try {
mainClass = super.getJarArchiveConfiguration().getManifest().getMainClass();
// 校验MainClass,要求MainClass必须不能为空
if (mainClass == null || mainClass.length() == 0) {
throw new MojoFailureException("MainClass is NULL !!!");
}
super.getLog().debug("MainClass is " + mainClass);
} catch (Exception e) {
throw new MojoFailureException("MainClass is null: " + e.getMessage(), e );
}
return mainClass;
}

private void handleArtifactExclude(Set<Artifact> artifacts) {
for (Artifact artifact : artifacts) {
String groupId = artifact.getGroupId(), artifactId = artifact.getArtifactId();
if (dependencyExclude.isExclude(groupId, artifactId)) {
getLog().info(String.format("GroupId[%s] ArtifactId[%s] belongs to DependencyExclude !!!", groupId, artifactId));
// 属于排除的名单之中
artifact.setScope(SCOPE_PROVIDED);
} else {
getLog().info(String.format("GroupId[%s] ArtifactId[%s] not belongs to DependencyExclude !!!", groupId, artifactId));
// 属于排除的名单之中
artifact.setScope(SCOPE_COMPILE);
}
}
}

private void excludeAllArtifactExclude(Set<Artifact> artifacts) {
for (Artifact artifact : artifacts) {
artifact.setScope(SCOPE_PROVIDED);
}
}

private void handleArtifactCompile(Set<Artifact> artifacts) {
for (Artifact artifact : artifacts) {
if (artifact.getScope().equals(SCOPE_PROVIDED)) {
// 将所有的provided设置为compile,以便于后续编译
artifact.setScope(SCOPE_COMPILE);
}
}
}

private File rename(MavenProject project, String finalName) throws IOException {
String srcJarPath = jarPath(project, finalName);
String dstJarPath = project.getBuild().getDirectory() +
File.separator + finalName + ".jar";
File dstFile = new File(dstJarPath);
FileUtils.copyFile(new File(srcJarPath), dstFile);
FileUtils.forceDelete(new File(srcJarPath));
return dstFile;
}

private String jarPath(MavenProject project, String finalName) {
return project.getBuild().getDirectory() +
File.separator + finalName + "-" + JAR_DEPENDENCE + ".jar";
}

private void verify(File jarFile, String mainClass) throws MojoFailureException {
try {
VerifyEngine verifyEngine = new VerifyEngine(getLog(), jarFile, mainClass, black, white);

verifyEngine.verify();

// 校验完成后将该jar包删除
// FileUtils.forceDelete(jarFile);

} catch (Exception e) {
getLog().error(e);
throw new MojoFailureException(e.getMessage());
}
}



private static void init() {
try {
black = AbstractContract.initBlack(loadBlackConf());
white = AbstractContract.initWhite(loadWhiteConf());
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private static List<String> loadWhiteConf() {

return resolveConfig(WHITE_CONF);
}

private static List<String> loadBlackConf() {
return resolveConfig(BLACK_CONF);
}

private static List<String> resolveConfig(String fileName) {
List<String> configs = new ArrayList<>();

try {
List<String> readLines = loadConfig(fileName);
if (!readLines.isEmpty()) {
for (String readLine : readLines) {
String[] lines = readLine.split(",");
configs.addAll(Arrays.asList(lines));
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
}

return configs;
}

public static List<String> loadConfig(String fileName) throws Exception {

return IOUtils.readLines(
ContractCompileMojo.class.getResourceAsStream("/" + fileName));
}
}

+ 9
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractConstant.java View File

@@ -0,0 +1,9 @@
package com.jd.blockchain.contract.maven;

public class ContractConstant {

public static final String METHOD_INIT = "<init>";

public static final String METHOD_CLINIT = "<clinit>";

}

+ 43
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractField.java View File

@@ -0,0 +1,43 @@
package com.jd.blockchain.contract.maven;

public class ContractField extends AbstractContract {

private String fieldName;

private String fieldType;

private boolean isStatic;

public ContractField(String className, String fieldName, String fieldType) {
this(className, fieldName, fieldType, false);
}

public ContractField(String className, String fieldName, String fieldType, boolean isStatic) {
this.className = format(className);
this.fieldName = fieldName;
this.fieldType = format(fieldType);
this.isStatic = isStatic;
}

public String getFieldName() {
return fieldName;
}

public String getFieldType() {
return fieldType;
}

public boolean isStatic() {
return isStatic;
}

@Override
public String toString() {
return "ContractField{" +
"className='" + className + '\'' +
", fieldName='" + fieldName + '\'' +
", fieldType='" + fieldType + '\'' +
", isStatic=" + isStatic +
'}';
}
}

+ 81
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractMethod.java View File

@@ -0,0 +1,81 @@
package com.jd.blockchain.contract.maven;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ContractMethod extends AbstractContract {

private String methodName;

private String[] paramTypes;

private String[] returnTypes;

private List<ContractField> fieldList = new ArrayList<>();

private List<ContractMethod> methodList = new ArrayList<>();

public ContractMethod(String className, String methodName) {
this(className, methodName, null, null);
}

public ContractMethod(String className, String methodName, String[] paramTypes, String[] returnTypes) {
this.className = format(className);
this.methodName = methodName;
this.paramTypes = paramTypes;
this.returnTypes = returnTypes;
}

public void addMethod(String className, String methodName, String[] paramTypes, String[] returnTypes) {
methodList.add(new ContractMethod(className, methodName, paramTypes, returnTypes));
}

public void addField(String className, String fieldName, String fieldType) {
this.fieldList.add(new ContractField(className, fieldName, fieldType));
}

public void addStaticField(String className, String fieldName, String fieldType) {
this.fieldList.add(new ContractField(className, fieldName, fieldType, true));
}

public String getMethodName() {
return methodName;
}

public String[] getParamTypes() {
return paramTypes;
}

public List<ContractField> getAllFieldList() {
return fieldList;
}

public List<ContractField> getClassFieldList(String cName) {
List<ContractField> classFieldList = new ArrayList<>();
if (!fieldList.isEmpty()) {
for (ContractField field : fieldList) {
if (field.getClassName().equals(cName)) {
classFieldList.add(field);
}
}
}
return classFieldList;
}

public List<ContractMethod> getMethodList() {
return methodList;
}

@Override
public String toString() {
return "ContractMethod{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", paramTypes=" + Arrays.toString(paramTypes) +
", returnTypes=" + Arrays.toString(returnTypes) +
", fieldList=" + fieldList +
", methodList=" + methodList +
'}';
}
}

+ 22
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/asm/ASMClassVisitor.java View File

@@ -0,0 +1,22 @@
package com.jd.blockchain.contract.maven.asm;

import com.jd.blockchain.contract.maven.ContractClass;
import com.jd.blockchain.contract.maven.ContractMethod;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class ASMClassVisitor extends ClassVisitor {

private ContractClass contractClass;

public ASMClassVisitor(ContractClass contractClass) {
super(Opcodes.ASM5);
this.contractClass = contractClass;
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor superMV = super.visitMethod(access, name, desc, signature, exceptions);
ContractMethod method = this.contractClass.method(name);
return new ASMMethodVisitor(superMV, method);
}
}

+ 108
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/asm/ASMMethodVisitor.java View File

@@ -0,0 +1,108 @@
package com.jd.blockchain.contract.maven.asm;

import com.jd.blockchain.contract.maven.ContractMethod;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;

import java.util.ArrayList;
import java.util.List;

public class ASMMethodVisitor extends MethodVisitor {

private ContractMethod method;

public ASMMethodVisitor(MethodVisitor mv, ContractMethod method) {
super(Opcodes.ASM5, mv);
this.method = method;
}

@Override
public void visitFieldInsn(int type, String cName, String fName, String fType) {
if (type == 178 || type == 179) {
this.method.addStaticField(cName, fName, fType);
} else {
this.method.addField(cName, fName, fType);
}
super.visitFieldInsn(type, cName, fName, fType);
}

@Override
public void visitMethodInsn(int type, String cName, String mName, String params, boolean b) {
ParamsAndReturn paramsAndReturn = resolveParamsAndReturn(params);
this.method.addMethod(cName, mName, paramsAndReturn.paramTypes, paramsAndReturn.returnTypes);
super.visitMethodInsn(type, cName, mName, params, b);
}

private ParamsAndReturn resolveParamsAndReturn(String params) {
// 格式:
// 1、(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
// 2、()I
// 3、(Ljava/lang/String;)V
// 4、()V
// 5、([Ljava/lang/Object;)Ljava/util/List; false
// 从上面分析可以得出:括号内的是入参,右括号后面的是返回值,其中V表示Void,即空;
String[] paramArray = params.split("\\)");
String paramTypeChars = "";
if (!paramArray[0].equals("(")) {
// 表明入参不为空
paramTypeChars = paramArray[0].split("\\(")[1];
}
String returnTypeChars = paramArray[1];
return new ParamsAndReturn(paramTypeChars, returnTypeChars);
}

static class ParamsAndReturn {

String[] paramTypes;

String[] returnTypes;

public ParamsAndReturn(String paramsTypeChars, String returnTypeChars) {
initParamsType(paramsTypeChars);
initReturnType(returnTypeChars);
}

private void initParamsType(String paramsTypeChars) {
List<String> paramList = handleTypes(paramsTypeChars);
if (!paramList.isEmpty()) {
this.paramTypes = new String[paramList.size()];
paramList.toArray(this.paramTypes);
}
}

private void initReturnType(String returnTypeChar) {
// 按照分号分隔
List<String> returnList = handleTypes(returnTypeChar);
if (!returnList.isEmpty()) {
this.returnTypes = new String[returnList.size()];
returnList.toArray(this.returnTypes);
}
}

private List<String> handleTypes(String typeChars) {
String[] types = typeChars.split(";");
List<String> typeList = new ArrayList<>();
if (types.length > 0) {
for (String type : types) {
if (type.length() > 0) {
if (type.startsWith("[L") && type.length() > 2) {
// 说明是数组
typeList.add(type.substring(2) + "[]");
} else if (type.startsWith("[") && type.length() > 1) {
// 说明是数组
typeList.add(type.substring(1));
} else if (type.startsWith("L") && type.length() > 1) {
// 说明是非基础类型
typeList.add(type.substring(1));
} else {
typeList.add(type);
}
}
}
}
return typeList;
}
}
}

+ 155
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/BlackList.java View File

@@ -0,0 +1,155 @@
package com.jd.blockchain.contract.maven.rule;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class BlackList {

public static final String COMMON_METHOD = "*";

public static final String INIT_METHOD = "init";

// 合约黑名单
private final Map<String, BlackClass> blackClassMap = new ConcurrentHashMap<>();

private final List<String> blackPackages = new ArrayList<>();

public synchronized BlackList addBlack(String className, String methodName) {
String trimClassName = className.trim();
BlackClass blackClass = blackClassMap.get(trimClassName);
if (blackClass != null) {
blackClass.addMethod(methodName);
} else {
blackClass = new BlackClass(trimClassName);
blackClass.addMethod(methodName);
blackClassMap.put(trimClassName, blackClass);
}
return this;
}

public synchronized BlackList addBlack(Class<?> clazz, String methodName) {
return addBlack(clazz.getName(), methodName);
}

public synchronized BlackList addBlack(Class<?> clazz) {
return addBlack(clazz.getName(), COMMON_METHOD);
}

public synchronized BlackList addBlackPackage(String packageName) {
blackPackages.add(packageName.trim() + "."); // 末尾增加一个点,防止后续判断是拼凑
return this;
}

public boolean isBlackClass(String className) {
if (isContainsPackage(className)) {
return true;
}
BlackClass blackClass = blackClassMap.get(className);
if (blackClass == null) {
return false;
}
return blackClass.isBlack();
}

public boolean isBlack(Class<?> clazz, String methodName) {

// 判断该Class是否属于黑名单
if (isCurrentClassBlack(clazz, methodName)) {
return true;
}
// 当前Class不是黑名单的情况下,处理其对应的父类和接口
// 获取该Class对应的接口和父类列表
Set<Class<?>> superClassAndAllInterfaces = new HashSet<>();

loadSuperClassAndAllInterfaces(clazz, superClassAndAllInterfaces);

// 循环判断每个父类和接口
for (Class<?> currClass : superClassAndAllInterfaces) {
if (isCurrentClassBlack(currClass, methodName)) {
return true;
}
}
return false;
}

public boolean isCurrentClassBlack(Class<?> clazz, String methodName) {

String packageName = clazz.getPackage().getName();
for (String bp : blackPackages) {
if ((packageName + ".").equals(bp) || packageName.startsWith(bp)) {
return true;
}
}
// 判断该类本身是否属于黑名单
String className = clazz.getName();
BlackClass blackClass = blackClassMap.get(className);
if (blackClass != null) {
// 判断其方法
return blackClass.isBlack(methodName);
}
return false;
}

public boolean isBlackField(Class<?> clazz) {
return isBlack(clazz, INIT_METHOD);
}

private boolean isContainsPackage(String className) {
for (String bp : blackPackages) {
if (className.equals(bp) || className.startsWith(bp)) {
return true;
}
}
return false;
}

private void loadSuperClassAndAllInterfaces(Class<?> currentClass, Set<Class<?>> allClassList) {
if (currentClass == null) {
return;
}

if (!allClassList.contains(currentClass)) {
allClassList.add(currentClass);
// 处理其父类
Class<?> superClass = currentClass.getSuperclass();
loadSuperClassAndAllInterfaces(superClass, allClassList);

// 处理其所有接口
Class<?>[] allInterfaces = currentClass.getInterfaces();
if (allInterfaces != null && allInterfaces.length > 0) {
for (Class<?> intf : allInterfaces) {
loadSuperClassAndAllInterfaces(intf, allClassList);
}
}
}
}

private static class BlackClass {

String className;

Set<String> methods = new HashSet<>();

BlackClass(String className) {
this.className = className;
}

void addMethod(String methodName) {
methods.add(methodName);
}

boolean isBlack(String methodName) {
// 假设method为*则表示所有的方法
if (methods.contains(COMMON_METHOD)) {
return true;
}
return methods.contains(methodName);
}

boolean isBlack() {
return isBlack(COMMON_METHOD);
}
}
}



+ 93
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/DependencyExclude.java View File

@@ -0,0 +1,93 @@
package com.jd.blockchain.contract.maven.rule;

import com.jd.blockchain.contract.maven.ContractCompileMojo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DependencyExclude {

private static final String COMMON_ARTIFACTID = "*";

private static final String CONFIG = "providers.conf";

private static final Map<String, List<Dependency>> DEPENDENCYS = new ConcurrentHashMap<>();

static {
try {
init();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private static void init() throws Exception {
List<String> readLines = ContractCompileMojo.loadConfig(CONFIG);
if (!readLines.isEmpty()) {
for (String line : readLines) {
// groupId/artifactId
String[] lines = line.split(",");
if (lines.length > 0) {
for (String depend : lines) {
String[] depends = depend.split("/");
if (depends.length == 2) {
String groupId = depends[0], artifactId = depends[1];
Dependency dependency = new Dependency(groupId, artifactId);
addDependency(dependency);
}
}
}
}
}
}

private synchronized static void addDependency(Dependency dependency) {
String groupId = dependency.groupId;
if (!DEPENDENCYS.containsKey(groupId)) {
List<Dependency> dependencies = new ArrayList<>();
dependencies.add(dependency);
DEPENDENCYS.put(groupId, dependencies);
} else {
List<Dependency> dependencies = DEPENDENCYS.get(groupId);
dependencies.add(dependency);
}
}

public boolean isExclude(String groupId, String artifactId) {
List<Dependency> dependencies = DEPENDENCYS.get(groupId);

if (dependencies == null || dependencies.isEmpty()) {
return false;
}

for (Dependency dependency : dependencies) {
if (dependency.isEqualArtifactId(artifactId)) {
return true;
}
}

return false;
}


static class Dependency {

String groupId;

String artifactId;

public Dependency(String groupId, String artifactId) {
this.groupId = groupId;
this.artifactId = artifactId;
}

public boolean isEqualArtifactId(String artiId) {
if (artifactId.equals(COMMON_ARTIFACTID)) {
return true;
}
return artifactId.equals(artiId);
}
}
}

+ 30
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/WhiteList.java View File

@@ -0,0 +1,30 @@
package com.jd.blockchain.contract.maven.rule;

import java.util.ArrayList;
import java.util.List;

public class WhiteList {

// 合约白名单(白名单通常数量较少,主要是JDChain内部包)
private final List<String> whiteClasses = new ArrayList<>();

public void addWhite(String className) {
whiteClasses.add(className.trim());
}

public boolean isWhite(Class<?> clazz) {
String className = clazz.getName();
return isWhite(className);
}

public boolean isWhite(String className) {
for (String white : whiteClasses) {
if (white.equals(className) || className.startsWith(white)) {
return true;
}
}
return false;
}
}



+ 169
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/ResolveEngine.java View File

@@ -0,0 +1,169 @@
package com.jd.blockchain.contract.maven.verify;

import com.alibaba.fastjson.JSON;
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractJarUtils;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.contract.EventProcessingAware;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.jd.blockchain.contract.ContractJarUtils.*;

public class ResolveEngine {

private Log LOGGER;

// private File jarFile;

private String mainClass;

// public ResolveEngine(Log LOGGER, File jarFile, String mainClass) {
public ResolveEngine(Log LOGGER, String mainClass) {
this.LOGGER = LOGGER;
// this.jarFile = jarFile;
this.mainClass = mainClass;
}

/**
* 校验当前项目中MainClass其是否满足JDChain合约写法
*
* @param mainClassJarFile
* @throws MojoFailureException
*/
public void verifyCurrentProjectMainClass(File mainClassJarFile) throws MojoFailureException {
// 校验MainClass
try {
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass start...", mainClassJarFile.getName()));
// 自定义ClassLoader,必须使用Thread.currentThread().getContextClassLoader()
// 保证其项目内部加载的Jar包无须再加载一次
URLClassLoader classLoader = new URLClassLoader(new URL[]{mainClassJarFile.toURI().toURL()},
Thread.currentThread().getContextClassLoader());

// 从MainClass作为入口进行MainClass代码校验
Class<?> mClass = classLoader.loadClass(mainClass);
ContractType.resolve(mClass);

// 校验完成后需要释放,否则无法删除该Jar文件
classLoader.close();

LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", mainClassJarFile.getName()));
} catch (Exception e) {
throw new MojoFailureException(e.getMessage());
}
}

public File verify(File defaultJarFile) throws MojoFailureException {
try {
// 检查jar包中所有的class的命名,要求其包名不能为com.jd.blockchain.*
LinkedList<String> totalClasses = loadAllClass(defaultJarFile);

if (!totalClasses.isEmpty()) {

for (String clazz : totalClasses) {

String dotClassName = dotClassName(clazz);

LOGGER.debug(String.format("Verify Dependency Class[%s] start......", dotClassName));
// 获取其包名
// 将class转换为包名
String packageName = class2Package(dotClassName);

if (ContractJarUtils.isJDChainPackage(packageName)) {
throw new IllegalStateException(String.format("Class[%s]'s package[%s] cannot start with %s !",
dotClassName, packageName, ContractJarUtils.JDCHAIN_PACKAGE));
}

LOGGER.debug(String.format("Verify Class[%s] end......", clazz));
}
}

// 处理完成之后,生成finalName-JDChain-Contract.jar
return compileCustomJar(defaultJarFile);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw new MojoFailureException(e.getMessage());
}
}

private String class2Package(String dotClassName) {

return dotClassName.substring(0, dotClassName.lastIndexOf("."));
}

private File compileCustomJar(File defaultJarFile) throws IOException {

String fileParentPath = defaultJarFile.getParentFile().getPath();

String jarFileName = defaultJarFile.getName();

String fileName = jarFileName.substring(0, jarFileName.lastIndexOf("."));

// 首先将Jar包转换为指定的格式
String dstJarPath = fileParentPath + File.separator +
fileName + "-temp-" + System.currentTimeMillis() + ".jar";

File srcJar = defaultJarFile, dstJar = new File(dstJarPath);

LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", defaultJarFile.getPath(), dstJarPath));
// 首先进行Copy处理
copy(srcJar, dstJar);

LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", defaultJarFile.getPath(), dstJarPath));

byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);

String finalJarPath = fileParentPath + File.separator + fileName + "-JDChain-Contract.jar";

File finalJar = new File(finalJarPath);

// 生成最终的Jar文件
copy(dstJar, finalJar, contractMFJarEntry(), txtBytes, null);

// 删除临时文件
FileUtils.forceDelete(dstJar);

return finalJar;
}

private ClassLoader verifyMainClass(File jarFile) throws Exception {
// 加载main-class,开始校验类型
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass start...", jarFile.getName()));
URL jarURL = jarFile.toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL});
Class<?> mClass = classLoader.loadClass(mainClass);
ContractType.resolve(mClass);
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", jarFile.getName()));
return classLoader;
}

private LinkedList<String> loadAllClass(File file) throws Exception {
JarFile jarFile = new JarFile(file);
LinkedList<String> allClass = new LinkedList<>();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (entryName.endsWith(".class")) {
// 内部类,不需要处理
if (!entryName.contains("$")) {
allClass.addLast(entryName.substring(0, entryName.length() - 6));
}
}
}
// Jar文件使用完成后需要关闭,否则可能会产生无法删除的问题
jarFile.close();

return allClass;
}
}

+ 224
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/VerifyEngine.java View File

@@ -0,0 +1,224 @@
package com.jd.blockchain.contract.maven.verify;

import com.jd.blockchain.contract.ContractJarUtils;
import com.jd.blockchain.contract.maven.ContractClass;
import com.jd.blockchain.contract.maven.ContractField;
import com.jd.blockchain.contract.maven.ContractMethod;
import com.jd.blockchain.contract.maven.asm.ASMClassVisitor;
import com.jd.blockchain.contract.maven.rule.BlackList;
import com.jd.blockchain.contract.maven.rule.WhiteList;
import org.apache.maven.plugin.logging.Log;
import org.objectweb.asm.ClassReader;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.jd.blockchain.contract.ContractJarUtils.loadAllClasses;


public class VerifyEngine {

private Log LOGGER;

private File jarFile;

private String mainClass;

private BlackList black;

private WhiteList white;

// 代表的只是当前方法,不代表该方法中的内部方法
private Set<String> haveManagedMethods = new HashSet<>();

// 代表的是处理的参数
private Set<String> haveManagedFields = new HashSet<>();

public VerifyEngine(Log LOGGER, File jarFile, String mainClass, BlackList black, WhiteList white) {
this.LOGGER = LOGGER;
this.jarFile = jarFile;
this.mainClass = mainClass;
this.black = black;
this.white = white;
}

public void verify() throws Exception {
// 加载所有的jar,然后ASM获取MAP
URL jarURL = jarFile.toURI().toURL();

URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarURL},
Thread.currentThread().getContextClassLoader());

// 解析Jar包中所有的Class
Map<String, ContractClass> allContractClasses = resolveClasses(jarClasses());

// 开始处理MainClass
verify(urlClassLoader, allContractClasses);

// 校验完成后需要释放ClassLoader,否则无法删除该Jar包
urlClassLoader.close();
}

public void verify(URLClassLoader urlClassLoader, Map<String, ContractClass> allContractClasses) throws Exception {
// 获取MainClass
String mainClassKey = convertClassKey(mainClass);
ContractClass mainContractClass = allContractClasses.get(mainClassKey);
if (mainContractClass == null) {
LOGGER.error(String.format("Load Main Class = [%s] NULL !!!", mainClass));
throw new IllegalStateException("MainClass is NULL !!!");
}
// 校验该Class中所有方法
Map<String, ContractMethod> methods = mainContractClass.getMethods();
if (!methods.isEmpty()) {
for (Map.Entry<String, ContractMethod> entry : methods.entrySet()) {
ContractMethod method = entry.getValue();
verify(urlClassLoader, allContractClasses, method);
}
}
}

public void verify(URLClassLoader urlClassLoader, Map<String, ContractClass> allContractClasses, ContractMethod method) throws Exception {
// 获取方法中涉及到的所有的Class及Method
// 首先判断该方法对应的Class是否由urlClassLoader加载
// 首先判断该ClassName对应方法是否处理过
String managedKey = managedKey(method);
if (haveManagedMethods.contains(managedKey)) {
return;
}
// 将该方法设置为已处理
haveManagedMethods.add(managedKey);
String dotClassName = method.getDotClassName();


Class<?> dotClass = urlClassLoader.loadClass(dotClassName);

if (dotClass == null) {
return;
}
String dotClassLoader = null;
ClassLoader classLoader = dotClass.getClassLoader();

if (classLoader != null) {
dotClassLoader = dotClass.getClassLoader().toString();
}

if (dotClassLoader != null && dotClassLoader.contains("URLClassLoader")) {

// 说明是URLClassLoader,这个需要先从黑名单和白名单列表中操作
// 首先判断是否是黑名单,黑名单优先级最高
if (black.isBlack(dotClass, method.getMethodName())) {
throw new IllegalStateException(String.format("Class [%s] Method [%s] is Black !!!", dotClassName, method.getMethodName()));
} else {
// 不是黑名单的情况下,判断是否为白名单
if (white.isWhite(dotClass)) {
return;
}
// 如果不属于白名单,则需要判断其子方法
List<ContractMethod> innerMethods = method.getMethodList();
if (!innerMethods.isEmpty()) {
for (ContractMethod innerMethod : innerMethods) {
// 需要重新从AllMap中获取,因为生成时并未处理其关联关系
ContractClass innerClass = allContractClasses.get(innerMethod.getClassName());
if (innerClass != null) {
ContractMethod verifyMethod = innerClass.method(innerMethod.getMethodName());
verify(urlClassLoader, allContractClasses, verifyMethod);
} else {
verify(urlClassLoader, allContractClasses, innerMethod);
}
}
}
List<ContractField> innerFields = method.getAllFieldList();
if (!innerFields.isEmpty()) {
for (ContractField innerField : innerFields) {
verify(urlClassLoader, innerField);
}
}
}
} else {
// 非URLClassLoader加载的类,只需要做判断即可
// 对于系统加载的类,其白名单优先级高于黑名单
// 1、不再需要获取其方法;
// 首先判断是否为白名单
if (white.isWhite(dotClass)) {
return;
}
// 然后判断其是否为黑名单
if (black.isBlack(dotClass, method.getMethodName())) {
throw new IllegalStateException(String.format("Class [%s] Method [%s] is Black !!!", dotClassName, method.getMethodName()));
}
}
}

public void verify(URLClassLoader urlClassLoader, ContractField field) throws Exception {
// 获取方法中涉及到的所有的Class及Method
// 首先判断该方法对应的Class是否由urlClassLoader加载
// 首先判断该ClassName对应方法是否处理过
String managedKey = managedKey(field);
if (haveManagedFields.contains(managedKey)) {
return;
}
// 将该字段设置为已读
haveManagedFields.add(managedKey);

Class<?> dotClass = urlClassLoader.loadClass(field.getDotClassName());

if (dotClass == null) {
return;
}

if (black.isBlackField(dotClass)) {
throw new IllegalStateException(String.format("Class [%s] Field [%s] is Black !!!", field.getDotClassName(), field.getFieldName()));
}
}

private Map<String, byte[]> jarClasses() throws Exception {
return loadAllClasses(jarFile);
}

private Map<String, ContractClass> resolveClasses(Map<String, byte[]> allClasses) {

Map<String, ContractClass> allContractClasses = new ConcurrentHashMap<>();

for (Map.Entry<String, byte[]> entry : allClasses.entrySet()) {
byte[] classContent = entry.getValue();
if (classContent == null || classContent.length == 0) {
continue;
}
String className = entry.getKey().substring(0, entry.getKey().length() - 6);

String dotClassName = ContractJarUtils.dotClassName(className);
if (white.isWhite(dotClassName) || black.isBlackClass(dotClassName)) {
continue;
}

ContractClass contractClass = new ContractClass(className);
ClassReader cr = new ClassReader(classContent);
cr.accept(new ASMClassVisitor(contractClass), ClassReader.SKIP_DEBUG);
allContractClasses.put(className, contractClass);
}
return allContractClasses;
}

private String convertClassKey(final String classKey) {
String newClassKey = classKey;
if (classKey.endsWith(".class")) {
newClassKey = classKey.substring(0, classKey.length() - 6);
}
newClassKey = newClassKey.replaceAll("\\.", "/");
return newClassKey;
}

private String managedKey(ContractMethod method) {
return method.getDotClassName() + "-" + method.getMethodName();
}

private String managedKey(ContractField field) {
return field.getDotClassName() + "-<init>-" + field.getFieldName();
}
}

+ 19
- 0
source/contract/contract-maven-plugin/src/main/resources/blacks.conf View File

@@ -0,0 +1,19 @@
java.io.File
java.io.InputStream
java.io.OutputStream
java.io.DataInput
java.io.DataOutput
java.io.Reader
java.io.Writer
java.io.Flushable
java.nio.channels.*
java.nio.file.*
java.net.*
java.sql.*
java.lang.reflect.*
java.lang.Class
java.lang.ClassLoader
java.util.Random
java.lang.System-currentTimeMillis
java.lang.System-nanoTime
com.jd.blockchain.ledger.BlockchainKeyGenerator-generate

+ 0
- 1
source/contract/contract-maven-plugin/src/main/resources/config.properties View File

@@ -1 +0,0 @@
blacklist=java.io,java.net,java.util.Random

+ 22
- 0
source/contract/contract-maven-plugin/src/main/resources/providers.conf View File

@@ -0,0 +1,22 @@
com.jd.blockchain/*
com.alibaba/fastjson
org.slf4j/*
org.apache.logging.log4j/*
org.aspectj/*
redis.clients/*
org.rocksdb/*
io.grpc/*
org.apache.commons/*
org.apache.httpcomponents/*
org.apache.logging.log4j/*
org.reflections/reflections
com.google.guava/guava
commons-cli/commons-cli
commons-codec/commons-codec
commons-httpclient/commons-httpclient
commons-io/commons-io
io.netty/*
org.slf4j/*
org.springframework.boot/*
org.springframework.security/*
org.springframework/*

+ 0
- 19
source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties View File

@@ -1,19 +0,0 @@
#PROJECT_BASE_DIR
PROJECT_BASE_DIR=E:\\gitCode\\block\\prototype\\
#LEDGER_BASE_CLASS_PATH
LEDGER_BASE_CLASS_PATH=E:\\gitCode\\block\\prototype\\libs\\

#deploy and execute the contract;
cParam=com.jd.blockchain.contract.AssetContract3
sParam=E:\\gitCode\\block\\prototype\\source\\sdk\\contract-sample\\src\\main\\java\\
eParam=utf-8
oParam=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\src\\test\\resources\\
host=127.0.0.1
port=8081
event = issue-asset
ownerPassword=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\ownerPassword.txt
ownerPubPath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\jd-com.pub
ownerPrvPath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\jd-com.priv
chainCodePath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\src\\test\\resources\\AssetContract3.contract
ledgerHash=6FEQDTQMnBGANpfX4haXuWHKHw5cZ6P1h2ocqwckYBxp4
contractArgs=101##999##abc

+ 3
- 0
source/contract/contract-maven-plugin/src/main/resources/whites.conf View File

@@ -0,0 +1,3 @@
com.jd.blockchain.*
java.nio.charset.Charset
com.alibaba.fastjson.*

+ 0
- 28
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/CheckImportsMojoTest.java View File

@@ -1,28 +0,0 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.CheckImportsMojo;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
* @Author zhaogw
* @Date 2019/3/1 21:27
*/
public class CheckImportsMojoTest extends AbstractMojoTestCase {
Logger logger = LoggerFactory.getLogger(CheckImportsMojoTest.class);

@Test
public void test1() throws Exception {
File pom = getTestFile( "src/test/resources/project-to-test/pom.xml" );
assertNotNull( pom );
assertTrue( pom.exists() );

CheckImportsMojo myMojo = (CheckImportsMojo) lookupMojo( "checkImports", pom );
assertNotNull( myMojo );
myMojo.execute();
}
}

+ 21
- 21
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractDeployMojoTest.java View File

@@ -1,21 +1,21 @@
package com.jd.blockchain.ledger;
import com.jd.blockchain.ContractDeployMojo;
import java.lang.reflect.Field;
/**
* for contract deploy and exe;
* @Author zhaogw
* @Date 2018/11/02 09:06
*/
public class ContractDeployMojoTest {
private ContractDeployMojo contractDeployMojo = new ContractDeployMojo();
private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException, IllegalAccessException {
Field field = contractDeployMojo.getClass().getDeclaredField(fieldName);//name为类Instance中的private属性
field.setAccessible(true);//=true,可访问私有变量。
Class<?> typeClass = field.getType();
field.set(contractDeployMojo, objValue);
}
}
//package com.jd.blockchain.ledger;
//
//import com.jd.blockchain.contract.maven.ContractDeployMojo;
//
//import java.lang.reflect.Field;
//
///**
// * for contract deploy and exe;
// * @Author zhaogw
// * @Date 2018/11/02 09:06
// */
//public class ContractDeployMojoTest {
// private ContractDeployMojo contractDeployMojo = new ContractDeployMojo();
//
// private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException, IllegalAccessException {
// Field field = contractDeployMojo.getClass().getDeclaredField(fieldName);//name为类Instance中的private属性
// field.setAccessible(true);//=true,可访问私有变量。
// Class<?> typeClass = field.getType();
// field.set(contractDeployMojo, objValue);
// }
//}

+ 50
- 0
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractTestBase.java View File

@@ -0,0 +1,50 @@
//package com.jd.blockchain.ledger;
//
//import org.apache.maven.model.Build;
//import org.apache.maven.project.MavenProject;
//import org.junit.Test;
//import org.springframework.core.io.ClassPathResource;
//
//import java.io.File;
//
//public class ContractTestBase {
//
// public static MavenProject mavenProjectInit() {
// MavenProject mavenProject = new MavenProject();
// mavenProject.setBuild(buildInit());
// mavenProject.setFile(file());
// return mavenProject;
// }
//
// public static File file() {
// String resDir = resourceDir();
// File file = new File(resDir);
// String path = file.getParentFile().getParentFile().getPath();
// return new File(path + File.separator + "src");
// }
//
// public static Build buildInit() {
// Build build = new Build();
// build.setDirectory(resourceDir());
// return build;
// }
//
// public static String resourceDir() {
// try {
// ClassPathResource classPathResource = new ClassPathResource("complex.jar");
// return classPathResource.getFile().getParentFile().getPath();
// } catch (Exception e) {
// throw new IllegalStateException(e);
// }
// }
//
// @Test
// public void testResourceDir() {
// System.out.println(resourceDir());
// }
//
// @Test
// public void testFile() {
// System.out.println(file().getPath());
// }
//}

+ 28
- 0
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java View File

@@ -0,0 +1,28 @@
//package com.jd.blockchain.ledger;
//
//import com.jd.blockchain.contract.maven.ContractVerifyMojo;
//import org.apache.maven.plugin.testing.AbstractMojoTestCase;
//import org.junit.Test;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import java.io.File;
//
///**
// * @Author zhaogw
// * @Date 2019/3/1 21:27
// */
//public class ContractVerifyMojoTest extends AbstractMojoTestCase {
// Logger logger = LoggerFactory.getLogger(ContractVerifyMojoTest.class);
//
// @Test
// public void test1() throws Exception {
// File pom = getTestFile( "src/test/resources/project-to-test/pom.xml" );
// assertNotNull( pom );
// assertTrue( pom.exists() );
//
// ContractVerifyMojo myMojo = (ContractVerifyMojo) lookupMojo( "contractVerify", pom );
// assertNotNull( myMojo );
// myMojo.execute();
// }
//}

+ 47
- 0
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest_.java View File

@@ -0,0 +1,47 @@
//package com.jd.blockchain.ledger;
//
//import com.jd.blockchain.contract.maven.ContractVerifyMojo;
//import org.apache.maven.project.MavenProject;
//import org.junit.Before;
//import org.junit.Test;
//
//import java.lang.reflect.Field;
//
//import static com.jd.blockchain.ledger.ContractTestBase.mavenProjectInit;
//
//public class ContractVerifyTest_ {
//
// private MavenProject project;
//
// private String finalName;
//
// @Before
// public void testInit() {
// project = mavenProjectInit();
// finalName = "complex";
// }
//
// @Test
// public void test() throws Exception {
// ContractVerifyMojo contractVerifyMojo = contractVerifyMojoConf();
// contractVerifyMojo.execute();
// }
//
// private ContractVerifyMojo contractVerifyMojoConf() throws Exception {
// ContractVerifyMojo contractVerifyMojo = new ContractVerifyMojo();
// // 为不影响其内部结构,通过反射进行私有变量赋值
// Class<?> clazz = contractVerifyMojo.getClass();
// Field projectField = clazz.getDeclaredField("project");
// Field finalNameField = clazz.getDeclaredField("finalName");
//
// // 更新权限
// projectField.setAccessible(true);
// finalNameField.setAccessible(true);
//
// // 设置具体值
// projectField.set(contractVerifyMojo, project);
// finalNameField.set(contractVerifyMojo, finalName);
//
// return contractVerifyMojo;
// }
//}

+ 67
- 67
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/MyProjectStub.java View File

@@ -1,67 +1,67 @@
package com.jd.blockchain.ledger;
import org.apache.maven.model.Build;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
import org.codehaus.plexus.util.ReaderFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author zhaogw
* date 2019/6/4 18:33
*/
public class MyProjectStub extends MavenProjectStub
{
/**
* Default constructor
*/
public MyProjectStub()
{
MavenXpp3Reader pomReader = new MavenXpp3Reader();
Model model;
try
{
model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) );
setModel( model );
}
catch ( Exception e )
{
throw new RuntimeException( e );
}
setGroupId( model.getGroupId() );
setArtifactId( model.getArtifactId() );
setVersion( model.getVersion() );
setName( model.getName() );
setUrl( model.getUrl() );
setPackaging( model.getPackaging() );
Build build = new Build();
build.setFinalName( model.getArtifactId() );
build.setDirectory( getBasedir() + "/target" );
build.setSourceDirectory( getBasedir() + "/src/main/java" );
build.setOutputDirectory( getBasedir() + "/target/classes" );
build.setTestSourceDirectory( getBasedir() + "/src/test/java" );
build.setTestOutputDirectory( getBasedir() + "/target/test-classes" );
setBuild( build );
List compileSourceRoots = new ArrayList();
compileSourceRoots.add( getBasedir() + "/src/main/java" );
setCompileSourceRoots( compileSourceRoots );
List testCompileSourceRoots = new ArrayList();
testCompileSourceRoots.add( getBasedir() + "/src/test/java" );
setTestCompileSourceRoots( testCompileSourceRoots );
}
/** {@inheritDoc} */
public File getBasedir()
{
return new File( super.getBasedir() + "/src/test/resources/project-to-test/" );
}
}
//package com.jd.blockchain.ledger;
//
//import org.apache.maven.model.Build;
//import org.apache.maven.model.Model;
//import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
//import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
//import org.codehaus.plexus.util.ReaderFactory;
//
//import java.io.File;
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * @author zhaogw
// * date 2019/6/4 18:33
// */
//
//public class MyProjectStub extends MavenProjectStub
//{
// /**
// * Default constructor
// */
// public MyProjectStub()
// {
// MavenXpp3Reader pomReader = new MavenXpp3Reader();
// Model model;
// try
// {
// model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) );
// setModel( model );
// }
// catch ( Exception e )
// {
// throw new RuntimeException( e );
// }
//
// setGroupId( model.getGroupId() );
// setArtifactId( model.getArtifactId() );
// setVersion( model.getVersion() );
// setName( model.getName() );
// setUrl( model.getUrl() );
// setPackaging( model.getPackaging() );
//
// Build build = new Build();
// build.setFinalName( model.getArtifactId() );
// build.setDirectory( getBasedir() + "/target" );
// build.setSourceDirectory( getBasedir() + "/src/main/java" );
// build.setOutputDirectory( getBasedir() + "/target/classes" );
// build.setTestSourceDirectory( getBasedir() + "/src/test/java" );
// build.setTestOutputDirectory( getBasedir() + "/target/test-classes" );
// setBuild( build );
//
// List compileSourceRoots = new ArrayList();
// compileSourceRoots.add( getBasedir() + "/src/main/java" );
// setCompileSourceRoots( compileSourceRoots );
//
// List testCompileSourceRoots = new ArrayList();
// testCompileSourceRoots.add( getBasedir() + "/src/test/java" );
// setTestCompileSourceRoots( testCompileSourceRoots );
// }
//
// /** {@inheritDoc} */
// public File getBasedir()
// {
// return new File( super.getBasedir() + "/src/test/resources/project-to-test/" );
// }
//}

BIN
source/contract/contract-maven-plugin/src/test/resources/complex.jar View File


+ 8
- 2
source/contract/contract-samples/pom.xml View File

@@ -27,6 +27,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>

</dependencies>

<build>
@@ -34,11 +40,11 @@
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>transfer</finalName>
<finalName>complex</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>com.jd.blockchain.contract.TransferContractImpl</mainClass>
<mainClass>com.jd.blockchain.contract.ComplexContractImpl</mainClass>
</manifest>
</archive>
<descriptorRefs>


+ 7
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java View File

@@ -0,0 +1,7 @@
package com.jd.blockchain.contract;

@Contract
public interface ComplexContract {
@ContractEvent(name = "read-key")
String read(String address, String key);
}

+ 12
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java View File

@@ -0,0 +1,12 @@
package com.jd.blockchain.contract;


import com.alibaba.fastjson.JSON;

public class ComplexContractImpl implements ComplexContract {
@Override
public String read(String address, String key) {
String json = JSON.toJSONString(address);
return System.currentTimeMillis() + "" + json;
}
}

+ 6
- 6
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/ECDSAUtils.java View File

@@ -7,6 +7,8 @@ import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
@@ -28,12 +30,10 @@ public class ECDSAUtils {

// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
// the curve equation is y^2 = x^3 + 7.
private static final X9ECParameters X9_PARAMS = SECNamedCurves.getByName("secp256k1");
private static final ECCurve CURVE = X9_PARAMS.getCurve();
private static final ECPoint ECDSA_G = X9_PARAMS.getG();
private static final BigInteger ECDSA_H = X9_PARAMS.getH();
private static final BigInteger ECDSA_N = X9_PARAMS.getN();
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, ECDSA_G,ECDSA_N,ECDSA_H);
private static final ECNamedCurveParameterSpec PARAMS = ECNamedCurveTable.getParameterSpec("secp256k1");
private static final ECCurve CURVE = PARAMS.getCurve();
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(
CURVE, PARAMS.getG(), PARAMS.getN(), PARAMS.getH());


//-----------------Key Generation Algorithm-----------------


+ 187
- 0
source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/KeyGenUtils.java View File

@@ -0,0 +1,187 @@
package com.jd.blockchain.crypto;

import java.util.Arrays;

import javax.crypto.SecretKey;

import com.jd.blockchain.utils.ConsoleUtils;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.BytesUtils;
import com.jd.blockchain.utils.io.FileUtils;
import com.jd.blockchain.utils.security.AESUtils;
import com.jd.blockchain.utils.security.DecryptionException;
import com.jd.blockchain.utils.security.ShaUtils;

public class KeyGenUtils {

private static final byte[] PUB_KEY_FILE_MAGICNUM = { (byte) 0xFF, 112, 117, 98 };

private static final byte[] PRIV_KEY_FILE_MAGICNUM = { (byte) 0x00, 112, 114, 118 };

/**
* 公钥编码输出为 Base58 字符;
*
* @param pubKey
* @return
*/
public static String encodePubKey(PubKey pubKey) {
byte[] pubKeyBytes = BytesUtils.concat(PUB_KEY_FILE_MAGICNUM, pubKey.toBytes());
String base58PubKey = Base58Utils.encode(pubKeyBytes);
return base58PubKey;
}

public static PubKey decodePubKey(String base58PubKey) {
byte[] keyBytes = Base58Utils.decode(base58PubKey);
return decodePubKey(keyBytes);
}

public static String encodePrivKey(PrivKey privKey, String base58Pwd) {
byte[] pwdBytes = Base58Utils.decode(base58Pwd);
return encodePrivKey(privKey, pwdBytes);
}

public static String encodePrivKey(PrivKey privKey, byte[] pwdBytes) {
byte[] encodedPrivKeyBytes = encryptPrivKey(privKey, pwdBytes);
String base58PrivKey = Base58Utils.encode(encodedPrivKeyBytes);
return base58PrivKey;
}

public static byte[] encryptPrivKey(PrivKey privKey, byte[] pwdBytes) {
SecretKey userKey = AESUtils.generateKey128(pwdBytes);
byte[] encryptedPrivKeyBytes = AESUtils.encrypt(privKey.toBytes(), userKey);
return BytesUtils.concat(PRIV_KEY_FILE_MAGICNUM, encryptedPrivKeyBytes);
}

/**
* @param encodedPubKeyBytes
* @return
*/
private static PubKey decodePubKeyBytes(byte[] encodedPubKeyBytes) {
byte[] pubKeyBytes = Arrays.copyOfRange(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM.length,
encodedPubKeyBytes.length);
return new PubKey(pubKeyBytes);
}

public static PrivKey decryptedPrivKeyBytes(byte[] encodedPrivKeyBytes, byte[] pwdBytes) {
// Read privKye;
SecretKey userKey = AESUtils.generateKey128(pwdBytes);
byte[] encryptedKeyBytes = Arrays.copyOfRange(encodedPrivKeyBytes, PRIV_KEY_FILE_MAGICNUM.length,
encodedPrivKeyBytes.length);
try {
byte[] plainKeyBytes = AESUtils.decrypt(encryptedKeyBytes, userKey);
return new PrivKey(plainKeyBytes);
} catch (DecryptionException e) {
throw new DecryptionException("Invalid password!", e);
}
}

public static PubKey readPubKey(String keyFile) {
String base58KeyString = FileUtils.readText(keyFile);
return decodePubKey(base58KeyString);
}

/**
* 解码公钥;
*
* @param encodedPubKeyBytes 从公钥;
* @return
*/
public static PubKey decodePubKey(byte[] encodedPubKeyBytes) {
if (BytesUtils.startsWith(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM)) {
// Read pubKey;
return decodePubKeyBytes(encodedPubKeyBytes);
}

throw new IllegalArgumentException("The specified bytes is not valid PubKey generated by the KeyGen tool!");
}

/**
* 从控制台读取加密口令,以二进制数组形式返回原始口令的一次SHA256的结果;
*
* @return
*/
public static byte[] readPassword() {
byte[] pwdBytes = ConsoleUtils.readPassword();
return ShaUtils.hash_256(pwdBytes);
}

/**
* 对指定的原始密码进行编码生成用于加解密的密码;
*
* @param rawPassword
* @return
*/
public static byte[] encodePassword(String rawPassword) {
byte[] pwdBytes = BytesUtils.toBytes(rawPassword, "UTF-8");
return ShaUtils.hash_256(pwdBytes);
}

/**
* 对指定的原始密码进行编码生成用于加解密的密码;
*
* @param rawPassword
* @return
*/
public static String encodePasswordAsBase58(String rawPassword) {
return Base58Utils.encode(encodePassword(rawPassword));
}

/**
* 从控制台读取加密口令,以Base58字符串形式返回口令的一次SHA256的结果;
*
* @return
*/
public static String readPasswordString() {
return Base58Utils.encode(readPassword());
}

public static PrivKey readPrivKey(String keyFile, String base58Pwd) {
return readPrivKey(keyFile, Base58Utils.decode(base58Pwd));
}

/**
* 从文件读取私钥;
*
* @param keyFile
* @param pwdBytes
* @return
*/
public static PrivKey readPrivKey(String keyFile, byte[] pwdBytes) {
String base58KeyString = FileUtils.readText(keyFile);
byte[] keyBytes = Base58Utils.decode(base58KeyString);
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) {
throw new IllegalArgumentException("The specified file is not a private key file!");
}
return decryptedPrivKeyBytes(keyBytes, pwdBytes);
}

public static PrivKey decodePrivKey(String base58Key, String base58Pwd) {
byte[] decryptedKey = Base58Utils.decode(base58Pwd);
return decodePrivKey(base58Key, decryptedKey);
}

public static PrivKey decodePrivKey(String base58Key, byte[] pwdBytes) {
byte[] keyBytes = Base58Utils.decode(base58Key);
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) {
throw new IllegalArgumentException("The specified file is not a private key file!");
}
return decryptedPrivKeyBytes(keyBytes, pwdBytes);
}

public static PrivKey decodePrivKeyWithRawPassword(String base58Key, String rawPassword) {
byte[] pwdBytes = encodePassword(rawPassword);
byte[] keyBytes = Base58Utils.decode(base58Key);
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) {
throw new IllegalArgumentException("The specified file is not a private key file!");
}
return decryptedPrivKeyBytes(keyBytes, pwdBytes);
}

public static boolean isPubKeyBytes(byte[] keyBytes) {
return BytesUtils.startsWith(keyBytes, PUB_KEY_FILE_MAGICNUM);
}

public static boolean isPrivKeyBytes(byte[] keyBytes) {
return BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM);
}
}

+ 62
- 13
source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CSRBuilder.java View File

@@ -16,6 +16,9 @@ import org.bouncycastle.util.encoders.Base64;

import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
* @author zhanglin33
@@ -25,16 +28,18 @@ import java.security.*;
*/
public class CSRBuilder {

private String BC = BouncyCastleProvider.PROVIDER_NAME;
private final String BC = BouncyCastleProvider.PROVIDER_NAME;

private PublicKey pubKey;
private PrivateKey privKey;

private String algoName;
private int keyLength;

public void init() {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
algoName = "SHA1withRSA";
keyLength = 2048;
KeyPairGenerator generator;
try {
generator = KeyPairGenerator.getInstance("RSA", BC);
@@ -47,10 +52,11 @@ public class CSRBuilder {
}
}

public void init(String algoName, int KeyLength) {
public void init(String algoName, int keyLength) {

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.algoName = algoName;
this.algoName = algoName;
this.keyLength = keyLength;

KeyPairGenerator generator;
KeyPair keyPair;
@@ -60,34 +66,69 @@ public class CSRBuilder {
switch (hashAndSignature[1]) {
case "RSA": {
generator = KeyPairGenerator.getInstance("RSA", BC);
generator.initialize(KeyLength);
keyPair = generator.generateKeyPair();
pubKey = keyPair.getPublic();
privKey = keyPair.getPrivate();
generator.initialize(keyLength);
break;
}

case "SM2": {
generator = KeyPairGenerator.getInstance("EC", BC);
if (KeyLength != 256) {
if (keyLength != 256) {
throw new CryptoException("SM3withSM2 with unsupported key length [" +
KeyLength +"] in CSR!");
keyLength +"] in CSR!");
}
generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
keyPair = generator.generateKeyPair();
pubKey = keyPair.getPublic();
privKey = keyPair.getPrivate();
break;
}

default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" +
KeyLength +"] in CSR!");
keyLength +"] in CSR!");
}
keyPair = generator.generateKeyPair();
pubKey = keyPair.getPublic();
privKey = keyPair.getPrivate();
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
throw new CryptoException(e.getMessage(), e);
}
}

public void init(String algoName, byte[] pubKeyBytes, byte[] privKeyBytes) {

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.algoName = algoName;
String[] hashAndSignature = algoName.split("with");

X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pubKeyBytes);
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privKeyBytes);

KeyFactory keyFactory;

try {
switch (hashAndSignature[1]) {
case "RSA": {
keyFactory = KeyFactory.getInstance("RSA");
privKey = keyFactory.generatePrivate(privKeySpec);
pubKey = keyFactory.generatePublic(pubKeySpec);
keyLength = (pubKey.getEncoded().length < 4096 / 8)? 2048: 4096;
break;
}

case "SM2": {
keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
privKey = keyFactory.generatePrivate(privKeySpec);
pubKey = keyFactory.generatePublic(pubKeySpec);
keyLength = 256;
break;
}

default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with the given key pair!");
}
} catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) {
throw new CryptoException(e.getMessage(), e);
}


}

public String buildRequest(String countryName, String stateName, String cityName,
String organizationName, String departmentName, String domainName,
String emailName) {
@@ -126,4 +167,12 @@ public class CSRBuilder {
public PrivateKey getPrivKey() {
return privKey;
}

public String getAlgoName() {
return algoName;
}

public int getKeyLength() {
return keyLength;
}
}

+ 16
- 0
source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CertParser.java View File

@@ -25,6 +25,7 @@ public class CertParser {
private String sigAlgName;
private String userName;
private String issuerName;
private int keyLength;

private Date startTime;
private Date endTime;
@@ -71,6 +72,17 @@ public class CertParser {
sigAlgName = userCert.getSigAlgName();
issuerName = userCert.getIssuerX500Principal().getName();
userName = userCert.getSubjectX500Principal().getName();

switch (sigAlgName) {
case "SM3WITHSM2": {
keyLength = 256;
break;
}
case "SHA1WITHRSA": {
keyLength = (pubKey.getEncoded().length < 4096 / 8)? 2048: 4096;
break;
}
}
}

// certificate string in Base64 format
@@ -121,6 +133,10 @@ public class CertParser {
return issuerName;
}

public int getKeyLength() {
return keyLength;
}

public Date getStartTime() {
return startTime;
}


+ 145
- 0
source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunctionTest.java View File

@@ -1,9 +1,13 @@
package com.jd.blockchain.crypto.service.pki;

import com.jd.blockchain.crypto.*;
import com.jd.blockchain.crypto.utils.CSRBuilder;
import com.jd.blockchain.crypto.utils.CertParser;
import com.jd.blockchain.utils.io.BytesUtils;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

import java.security.*;
import java.util.Random;

import static com.jd.blockchain.crypto.CryptoAlgorithm.*;
@@ -125,4 +129,145 @@ public class SHA1WITHRSA2048SignatureFunctionTest {
resolvedSignatureDigest.getAlgorithm());
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
}

@Test
public void testWithCSRAndCert() {

String countryName = "CN";
String stateName = "Beijing";
String cityName = "Beijing";
String organizationName = "JD.com";
String departmentName = "Blockchain Department";
String domainName = "ledger.jd.com";
String emailName = "zhanglin33@jd.com";


String publicKeyStr = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c91e978897a36b" +
"30a57d265807441b0eff40c5572ecf029cd0cb2999b715edd2d5345c7b60c003075b1352629d03b943d08b25bfc5245" +
"a400f9ecbc1757394eac452d6316bf90cfcff5edfc427e277aa5266e89b1b2daa2e69dad5575515f49417c9ff332c83" +
"0dcd5537381f08e00b11123ad947bb11b18666d264ab5d8cdc92d0967fd7e0e6677746e2f01270d0594f74cda4e9d77" +
"4c6f3824499896bfb6424684af260d71b57a1366b741104fc647d9e38de055568daad60c116686e4afa1e9c83e9e30c" +
"7216e61353da2f75b2dde2c0ae870cf0ccc90490d1e22ecccbf3985d30933689847e6faf946993f930f83ac5b816075" +
"793a9a6df20727552a21be30203010001";

String privateKeyStr = "308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100c91e" +
"978897a36b30a57d265807441b0eff40c5572ecf029cd0cb2999b715edd2d5345c7b60c003075b1352629d03b943d08" +
"b25bfc5245a400f9ecbc1757394eac452d6316bf90cfcff5edfc427e277aa5266e89b1b2daa2e69dad5575515f49417" +
"c9ff332c830dcd5537381f08e00b11123ad947bb11b18666d264ab5d8cdc92d0967fd7e0e6677746e2f01270d0594f7" +
"4cda4e9d774c6f3824499896bfb6424684af260d71b57a1366b741104fc647d9e38de055568daad60c116686e4afa1e" +
"9c83e9e30c7216e61353da2f75b2dde2c0ae870cf0ccc90490d1e22ecccbf3985d30933689847e6faf946993f930f83" +
"ac5b816075793a9a6df20727552a21be30203010001028201003975637e93300d8a2ee573e47762f6461117cca96d46" +
"982cfc1be6ed3318f142a845d6dc2ad680a703d69fd56b9d6a3b1d23fbeb6f63c4e303736f2bfca5c2585631825f494" +
"534783d6f3a07bd0b5efbcaa1faf7814ac9118c8d8820f4be9a8b0ac6db819fc86b538bf284369d9f009a667668a82d" +
"224f7122041eddb492ef5b02d462aa11bc550bf3785a5d7538043586cfb0cd5c313a4746f22a5d4a89a412b279a7517" +
"176b1858a9677a1a60605aa0b2a7d260cf2e9e23a0e67c4a23ac046c62973239e84874c3695cc3f34073a62bd50b597" +
"ee06092a93fa6e41303ab4d2293ffad4c8db06e6516ae0a26a4d681305c3b7d535b540a638ca6cff1ce483750281810" +
"0e39967c5b287bd319b448255a1033591c74f4d688eb71f89a674cdb1be999e9abcf40e6b7f0bb3054262d7625002da" +
"7d34e56055ee130b66d682a0b9f8ea240a7e2dd1ff3f4b32f3bd352ba0a5dffc0315da34922493c267597787222213b" +
"f87d99fbd2a809c2647a1937cd1e303d746373db7c409a2ef33f8c06bb838bc612702818100e2374c71db5f0b4a199f" +
"f9d646a1785a84383a14aceb506f515b380c69ff45b51d0e941f55f0a234d8a3ee30bed656142bb5b985e462c44d234" +
"cfd424ecd6ca5fc70503862978ffe42b45bd698a99091d6fc65e2d85652e0ef56c52e8e05a6c5e879922c1d794e22f3" +
"51998217b5c6637a6abb716bf90cd1f23a2eedcdfface50281805d28a872224e2f2183e539d7e4ccd47b73f240c4004" +
"e72493c69e8dbcd2141eb22565f249edee20ad00e770c95a5655b0470b2cad964d030eab293292bfa62802cff824a10" +
"d52de8d8545024346106dd186fb53ef05bcea1d0dbfce2fac1cc8ec583fdc0ccdd9d498a983cea081ac55dc734aae84" +
"1ed802d6caf0e285c88b6d702818068b2a752daf1364c6967bd3e0b1a98956c3489cd1feb19232c4847bc97226aa4d4" +
"79f6dc39ee51649c0fe321f471470db6dd38ac5b73caded8c3bd437f2d5c67c65a450693bb0a0de7d989d7dc783e4d0" +
"16f77c871d02233b1123bd8bc2aa97157934cafd6445a819a93ddb4743cd141215b5cbdb5f7629398c48d0bcb17d671" +
"028181009282554329b89bcb2236a7e2a5bff53627e3ca7cc792d65236085741bc62a3f5767654722af561eff175664" +
"1af60e3d3959f63f0fec00cb29443ffca4ff751a76ecc6fa192ebe08ec9f643b9bb0d11bc90c1e850f0528ef223ea5f" +
"e4b4c107cc3a9eb26e6b84d74d87acbf7cc760cd788cbc30f95f8399077b25cdd924604c01";

String expectedCSR = "MIIC4jCCAcoCAQAwgZwxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW" +
"5nMQ8wDQYDVQQKDAZKRC5jb20xHjAcBgNVBAsMFUJsb2NrY2hhaW4gRGVwYXJ0bWVudDEWMBQGA1UEAwwNbGVkZ2VyLmpkL" +
"mNvbTEgMB4GCSqGSIb3DQEJARYRemhhbmdsaW4zM0BqZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ" +
"HpeIl6NrMKV9JlgHRBsO/0DFVy7PApzQyymZtxXt0tU0XHtgwAMHWxNSYp0DuUPQiyW/xSRaQA+ey8F1c5TqxFLWMWv5DPz" +
"/Xt/EJ+J3qlJm6JsbLaouadrVV1UV9JQXyf8zLIMNzVU3OB8I4AsREjrZR7sRsYZm0mSrXYzcktCWf9fg5md3RuLwEnDQWU" +
"90zaTp13TG84JEmYlr+2QkaEryYNcbV6E2a3QRBPxkfZ443gVVaNqtYMEWaG5K+h6cg+njDHIW5hNT2i91st3iwK6HDPDMy" +
"QSQ0eIuzMvzmF0wkzaJhH5vr5Rpk/kw+DrFuBYHV5Oppt8gcnVSohvjAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEALKHw" +
"BrlppbN+CSJwHxO99rv2XVD7L8lwwiMqdMzoNHxZUoob4AcGS3Iyxy6obX8fZh7DCA4nN0AmvrJCmWD3hCLclWKlwXTwvFe" +
"WIeB4xEB9MVPV6/Hs/QaI9Rjhd+O/Alfzov8y+KyYHEWmwxHj2RtQm1ZeulELzMvRjsqP+m5tOM1hLnPMU+AF1tZ9Fc7Jbm" +
"7Dwh6TAPpmaH1aVbHsnlZyCp8K4nMozVogcXJqg3qsbeJ6c/TofL0fURqiTJxLKMC0aD0TwVcNwDWEmc8cpqGheG1g6UF5l" +
"QBpeR2Br4f3LXJgr1Op1RxRy6I+X7h1IL38Q3jAOoU4y04O/+an7g==";

String expectedUserCert = "MIIERjCCAy6gAwIBAgIFIChmYJgwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVB" +
"AoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4X" +
"DTE5MDgyODA2MzEyNVoXDTIxMDgyODA2MzEyNVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTE" +
"RMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MT" +
"IyMjkyOTVANTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMkel4iXo2swpX0mWAdEGw7/QMVXLs8CnNDLKZm3F" +
"e3S1TRce2DAAwdbE1JinQO5Q9CLJb/FJFpAD57LwXVzlOrEUtYxa/kM/P9e38Qn4neqUmbomxstqi5p2tVXVRX0lBfJ/zMs" +
"gw3NVTc4HwjgCxESOtlHuxGxhmbSZKtdjNyS0JZ/1+DmZ3dG4vAScNBZT3TNpOnXdMbzgkSZiWv7ZCRoSvJg1xtXoTZrdBE" +
"E/GR9njjeBVVo2q1gwRZobkr6HpyD6eMMchbmE1PaL3Wy3eLArocM8MzJBJDR4i7My/OYXTCTNomEfm+vlGmT+TD4OsW4Fg" +
"dXk6mm3yBydVKiG+MCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GC" +
"GCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEw" +
"L6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjY2NTAuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQ" +
"UOTy45HymVDivPwA83lRoMpShasQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQ" +
"A7NFkDMV1mRV/07DJUdZJzvkm+QihhpLp7D2dUblCCEt0jjY5RdLiWG7HvJnlPTThiSkiejEO0Fy1cQzA5jYRhwp+70X8X9" +
"bt5jEBP/V4PyRXKKEvKZMdppLIeVI6rZk/gJzPh2FQYv3qWaINilxLOBP8Qa0kdMBwo6D6/MYwnSGv5zP4NLFUysLUJiKoM" +
"lAzEQSPNnkYRX6nogpkdN91/xgH3GA7fiihrjm5oxMAupCli9LQqvlUvRtv5EKIN9c+ixCAYFagG9IIjMDXbDne77n15i01" +
"420N8sjfTlr9v3W0v1gBSzjzFOT+TTTUtrjfO/Vm8iqq+z22QKIXgYjSF";

String issuerCert =
"-----BEGIN CERTIFICATE-----\n" +
"MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" +
"VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" +
"QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" +
"NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" +
"bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" +
"RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" +
"jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" +
"jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" +
"bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" +
"RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" +
"0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" +
"t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" +
"aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" +
"Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" +
"MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" +
"AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" +
"3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" +
"/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" +
"/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" +
"fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" +
"OMRZvB7FRyE9IfwKApngcZbA5g==\n" +
"-----END CERTIFICATE-----";

byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr);
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr);

CSRBuilder builder = new CSRBuilder();
builder.init("SHA1withRSA", rawPublicKeyBytes, rawPrivateKeyBytes);

String csr = builder.buildRequest(countryName,stateName,cityName,
organizationName,departmentName,domainName,
emailName);

assertEquals(expectedCSR,csr);

CertParser parser = new CertParser();
parser.parse(expectedUserCert,issuerCert);

PublicKey rawPublicKeyInCert = parser.getPubKey();
// check that the public key in inputs and the public key in certificate are consistent
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded());

String algoName = parser.getSigAlgName();
int keyLength = parser.getKeyLength();
String length = String.valueOf(keyLength);
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase());

CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo);
assertNotNull(algorithm);
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);

PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes);
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes);

// signTest
byte[] data = new byte[1024];
Random random = new Random();
random.nextBytes(data);

SignatureDigest signature = signatureFunction.sign(privKey, data);
assertTrue(signatureFunction.verify(signature, pubKey, data));
}
}

+ 186
- 0
source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunctionTest.java View File

@@ -1,9 +1,13 @@
package com.jd.blockchain.crypto.service.pki;

import com.jd.blockchain.crypto.*;
import com.jd.blockchain.crypto.utils.CSRBuilder;
import com.jd.blockchain.crypto.utils.CertParser;
import com.jd.blockchain.utils.io.BytesUtils;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

import java.security.PublicKey;
import java.util.Random;

import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY;
@@ -125,4 +129,186 @@ public class SHA1WITHRSA4096SignatureFunctionTest {
resolvedSignatureDigest.getAlgorithm());
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
}

@Test
public void testWithCSRAndCert() {

String countryName = "CN";
String stateName = "Beijing";
String cityName = "Beijing";
String organizationName = "JD.com";
String departmentName = "Blockchain Department";
String domainName = "ledger.jd.com";
String emailName = "zhanglin33@jd.com";


String publicKeyStr = "30820222300d06092a864886f70d01010105000382020f003082020a0282020100b40edee83b609e" +
"aa001f2496f95d2f3302513306ec9a8e7fce0d2e141fce7ee357a7465314c3f5f4b08cb6c95803c368ddbfedba483cb" +
"5c45914037ceee5783fc971a12ef9b0e4158dc379b59499eee629324a9beb350c4c10e50837345be128b91f43a03381" +
"758bbefe41c45712e4b5fdd5bde780167283706b24e37dd753db65b4c6b3e49cd8be825665d9a29a24b77e76473df02" +
"2327873555aa33ba2ffcc766cbefedc46ec868d10f817822540eaf5754c074dd6d428355ce24a058a4c9ce41e48aad5" +
"92e7955cf93d779d03d3acf25ae271346a9e4255e4ed902ae016032b04efbee98f43cd767653e089b37540e537aede9" +
"dbc04f8f1a858b2764b9eedac80b6a8da5ff02aab4be94e071c70718fde7227cdefec31600a1c55bac16f4de9dea8ab" +
"7824c1ec783b818dfe005f040a3f6872b1c7a6c31a66c1b06eb8d872a23d1b4fdadf9eed58f93b2a2bc145638a79a81" +
"904d39b22128ced18a2556c21888ed1ec8ad59bd6764f1ea16eb7f3574c53166f0827b5072d23017bd725adeb63eeb2" +
"29a4e78d4d7426e936753902bb51e3cd90630314f4ab41272a9e36cb668b2ba9c2ebc02e9ef0c377c88482e839f2f4d" +
"5c8efcfbe1280e52c6bdf80aa487ae03ff9dd9fd981f78172bc1141ce6031b0b8915658d830c696662507d3cf4ddba8" +
"7daabf97c15cbef58b15e84f16f879328c7c65076d94fc6b4514549831850203010001";

String privateKeyStr = "30820942020100300d06092a864886f70d01010105000482092c308209280201000282020100b40e" +
"dee83b609eaa001f2496f95d2f3302513306ec9a8e7fce0d2e141fce7ee357a7465314c3f5f4b08cb6c95803c368ddb" +
"fedba483cb5c45914037ceee5783fc971a12ef9b0e4158dc379b59499eee629324a9beb350c4c10e50837345be128b9" +
"1f43a03381758bbefe41c45712e4b5fdd5bde780167283706b24e37dd753db65b4c6b3e49cd8be825665d9a29a24b77" +
"e76473df022327873555aa33ba2ffcc766cbefedc46ec868d10f817822540eaf5754c074dd6d428355ce24a058a4c9c" +
"e41e48aad592e7955cf93d779d03d3acf25ae271346a9e4255e4ed902ae016032b04efbee98f43cd767653e089b3754" +
"0e537aede9dbc04f8f1a858b2764b9eedac80b6a8da5ff02aab4be94e071c70718fde7227cdefec31600a1c55bac16f" +
"4de9dea8ab7824c1ec783b818dfe005f040a3f6872b1c7a6c31a66c1b06eb8d872a23d1b4fdadf9eed58f93b2a2bc14" +
"5638a79a81904d39b22128ced18a2556c21888ed1ec8ad59bd6764f1ea16eb7f3574c53166f0827b5072d23017bd725" +
"adeb63eeb229a4e78d4d7426e936753902bb51e3cd90630314f4ab41272a9e36cb668b2ba9c2ebc02e9ef0c377c8848" +
"2e839f2f4d5c8efcfbe1280e52c6bdf80aa487ae03ff9dd9fd981f78172bc1141ce6031b0b8915658d830c696662507" +
"d3cf4ddba87daabf97c15cbef58b15e84f16f879328c7c65076d94fc6b451454983185020301000102820200063fece" +
"3452a579f817513454d3efb842afcac077dbf689a4d89de13533e4cdfb1bb6be0b6dc0d65b29a13bf1dd7b598e67782" +
"b6204b4128e149a54c59136c6ed45c661296169a78180d54a46595c939c26ccd33a7c095de6f08b01610726ef885a26" +
"cebbad5efc14bbe1204d15be5c5de5b64a5cc279b4e6e20bded4a8126973b2ac0e9de11c6a1282f7d060693909a30e0" +
"c49cc500bedd38ed99c18830a26dd39f772aabf527410d54ed338db022d674f21f1332d3b5d5f67234a58a97300d130" +
"aed0d46effc2b4e4895665934188d0c75749e26ca5b97645957989530657b332b4ef202b3d70fe2e07d0d526240fbe1" +
"68e320357be0f54e18008a233a8137e23ca1c54074b31c57eebee49bf2f1c66ea97a2c846a8d26680b97e1240d6763e" +
"60bcd8d696c806362b18bf0504a39e4d465a9548091dbe97c36f6d8e038d95a72c0a88ff524dc81fe0ed2afd69f4251" +
"1a90687a4c632c812234a19a7312b2dea3fcd4515800eca700733b0f83509184fe8d3cd21385f0ef0cec37c433d354f" +
"aed61662a62902c8708c81e2af20898f649c1bafd600baa0409c943cf82bc90ea20a8972da7ab3a252f4f08df2509de" +
"e1dacfe787eef4d60c0c92ec7a3c6277d7be39deed7704ac721d8efd138a410d632a32535142cf977b09d9fb680bc96" +
"c538c00440d5e1ed71f8510e6524e564d69a24d03f1a9a0c326b421e32550801c890282010100e8d72f8f1fbeada724" +
"3e6df25337a2e7fc43e3d4f39877f89abb3b5e453f20f339a1f35e0a2847122f0bd835e6b43fd276f447da04f85cfca" +
"0fa8bf49b313239e36f9595ef1bfb9b8247bf01cc407dfc444421161a5b2e96d4d1d90cea185945e9447d21a2d8a461" +
"f43dff9ba58043feeb49552a3bf2472eea59b2aa8631048c76a15898065be0ef957d4802c827e30339d66ad7aed5851" +
"a5896f12d33f45800dcb10859531c590af7a75e9fa81f1d937a287fb6b066d58720584af2ae161e083681655ae77f48" +
"34bfe0accf1d12bbdd8c2644f78b207cfcb2dedf9fe7d29e1ae5c2a5623f5a1770db27d2636450c79fd39bce39f009b" +
"598e0298e1f77bf8d3d0282010100c5f7af9258a42da93204cecb71c544397bc16691cf0d41308fbd3b88eca7d101d1" +
"377dfe3b7e66707d3e5543b21033ab6c5b0de577740c6e335f512eeb2a839c3f2baeca4ce80e3fbd8fb93fa983e1719" +
"5c5fee63bc163df334a80f2767871e3434adc0bc7030dea44fce414a08da7e918e6f030cfb20b2d29033e9ef1be3e08" +
"ef1f50df0c9325a20ff01d0b7a06761403ae3498aea8bad93110d61a6386d470e630990029e2cb098de40fafa330911" +
"6c3c6de180b7fa41ae14553e891148ab53e970ce372b1777826983baaccac08290e343761d8daa2505f1dc45b8511a3" +
"6e2d0909237be9ae7ebbaa00b31de1224f32959e4e6f3428140ca8e1e5580789e902820100674075609c8d2be880940" +
"6a17cf1a1160ab1f8684895862e023fa0f60ef30da38e1d1914cca04bd3ee74ec2e0ade47a70705108fc7c0734bbbff" +
"1eed1b9cd74f00624d0d2df954bc032bd9b1ec6774f6d736f70d1c26ef2407bffee65130f6f59f99b57ba3013af40d2" +
"12926565fe8c734835276e61a6c228bddb6f3138acd1f94c3bbcbbe9623cb5a9931c3ba0aa60a9a2d5137cfd9f3aa59" +
"3aa63c8b5b8162f07ab8df1391f092827bffe400e3bb73d8a9f8e88495357f3482b2c9a7153bc01c9b88dca4e7b6975" +
"db73e2aa213daa7462cfa4c63afc67d30bcd0a1d2657da323dc0b06e45d09240cab3e0ac1436922a0ede8a79ca0519d" +
"375a7621d23269690282010100bbc1299716d2bf2b94f0d260494ada65da6596adfb3d8af24fa11d71c36175eccf4c5" +
"e065cce88c16f474afea546907aa88dc3243aa2a9976ac99fe96bc82a8269b738534d9558ce432ea87724829bb26a66" +
"1a56a99dc4e6cf727dd17762cc40ca759934e24e9747f49e14832bb2ade97960adb4dd86f2eaa5d719f10d3d6d00742" +
"9b33d98638671a9c40507f9775f4da41ff86a465c68b9ccbb371458086c3b9755c8064bb378f55ac94dc73a72b96869" +
"cd969e1f69b36e7af091a024d8e2a4faf3af999811904937f171c58fd028fd272786cf1a286180f074fee1fdd6b8b5a" +
"9a8c42e0f3b95ef4474fbace54dbc887865467b0524e64dfda3be7b117e34e1028201001a7e846231c34400c1f704e7" +
"fec6e46c87d61f269b71942bc9cc72005ba30eea3db5d0e5b0b754f7a00b96c883399982b5b3a9916765c5ed9129e44" +
"a791ce6892f85758c637bc040da132b8f0cd0ac36ba3aae9334414a77f0b50c0aa03643bfd59b9a621342a4807e46fc" +
"52a5a12fd3ff6762e181c40c2baf3653043c836b14700463af5d68a2a2897897edb5f217d655d5bcd24e7910062f40e" +
"00f19e2f94b45efbbf60cbf734830756baf72dcfca8d2858ca5df63336999474945f3744a96e4ce23f9067bbca849ef" +
"1048cba3a4aad73ed73b0fcd8c2e9f6d06aa768548d7107aa58d9d296f853543f6569e4dd33270540d983460773794f" +
"e9196fc5a54cd";

String expectedCSR = "MIIE4jCCAsoCAQAwgZwxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW" +
"5nMQ8wDQYDVQQKDAZKRC5jb20xHjAcBgNVBAsMFUJsb2NrY2hhaW4gRGVwYXJ0bWVudDEWMBQGA1UEAwwNbGVkZ2VyLmpkL" +
"mNvbTEgMB4GCSqGSIb3DQEJARYRemhhbmdsaW4zM0BqZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0" +
"Dt7oO2CeqgAfJJb5XS8zAlEzBuyajn/ODS4UH85+41enRlMUw/X0sIy2yVgDw2jdv+26SDy1xFkUA3zu5Xg/yXGhLvmw5BW" +
"Nw3m1lJnu5ikySpvrNQxMEOUINzRb4Si5H0OgM4F1i77+QcRXEuS1/dW954AWcoNwayTjfddT22W0xrPknNi+glZl2aKaJL" +
"d+dkc98CIyeHNVWqM7ov/Mdmy+/txG7IaNEPgXgiVA6vV1TAdN1tQoNVziSgWKTJzkHkiq1ZLnlVz5PXedA9Os8lricTRqn" +
"kJV5O2QKuAWAysE777pj0PNdnZT4ImzdUDlN67enbwE+PGoWLJ2S57trIC2qNpf8CqrS+lOBxxwcY/ecifN7+wxYAocVbrB" +
"b03p3qireCTB7Hg7gY3+AF8ECj9ocrHHpsMaZsGwbrjYcqI9G0/a357tWPk7KivBRWOKeagZBNObIhKM7RiiVWwhiI7R7Ir" +
"Vm9Z2Tx6hbrfzV0xTFm8IJ7UHLSMBe9clretj7rIppOeNTXQm6TZ1OQK7UePNkGMDFPSrQScqnjbLZosrqcLrwC6e8MN3yI" +
"SC6Dny9NXI78++EoDlLGvfgKpIeuA/+d2f2YH3gXK8EUHOYDGwuJFWWNgwxpZmJQfTz03bqH2qv5fBXL71ixXoTxb4eTKMf" +
"GUHbZT8a0UUVJgxhQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggIBAKowJTG9mZLbDHRndmDUd7PWrq1AiCdk6DStV39B/REF" +
"OrMYcW9X4Ak69fhXQDtD4gu2lKtumDY0oJ8xleM2FHUSzdooTWb7P/QtCIBy27sH6nvlefRWi7ngSTNJlDmwgr0l07UzZU1" +
"Yl/ZULn0XlNAFal+qt+4ZNdiulNwkL6IofXV/8vqOeQw5iICDBYHItyY/mqD8IIaClVd8yNpEuE/W9GdJIDNXQjpug+BxL/" +
"FbjAs6P3ZzJboedJE5urbru2jjb7atl3w/eDo4r6+XNSD8d1PgVmVhzN2WpUWsZNeH2jd9AA6436GjsBssgSRKEc3FTJ+lO" +
"0Jw2d8GewXXkIv8CT4L3BFwqZhGQt27wlb87+W4dIC05JIaJx52869dvu1ky1CL73GROXeS8rVYJsPwVmK2xy3QTaeHGEQh" +
"kiVNeV1cc3mll2z7fgbkjPD8zDNBWUdzSXQMzecY1CBD02iz6LaHfvkI7gXXoiIf1cJrnLtYhv3lG45jKr0E45/Wn7oXmYk" +
"RM4/zHO4KnY7Pp3b3QTgkRJaPnZiG7aiCrdnTIopDSGpTWSPWDLjgwgaCPPz5Pd2Fk+SAE98o7Cu8O0vxMASpd4liaedASE" +
"n6hnrvcTkFLLG2ecZzJZ0aEqPi4es0FqlqVZrLPH2UYpECgfhkGQQKAx4eRTAZFhz1GSkd";

String expectedUserCert = "MIIFRjCCBC6gAwIBAgIFIChmYWIwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVB" +
"AoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4X" +
"DTE5MDgyODA4MDAxMVoXDTIxMDgyODA4MDAxMVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTE" +
"RMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MT" +
"IyMjkyOTVANzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQO3ug7YJ6qAB8klvldLzMCUTMG7JqOf84NLhQfz" +
"n7jV6dGUxTD9fSwjLbJWAPDaN2/7bpIPLXEWRQDfO7leD/JcaEu+bDkFY3DebWUme7mKTJKm+s1DEwQ5Qg3NFvhKLkfQ6Az" +
"gXWLvv5BxFcS5LX91b3ngBZyg3BrJON911PbZbTGs+Sc2L6CVmXZopokt352Rz3wIjJ4c1Vaozui/8x2bL7+3Ebsho0Q+Be" +
"CJUDq9XVMB03W1Cg1XOJKBYpMnOQeSKrVkueVXPk9d50D06zyWuJxNGqeQlXk7ZAq4BYDKwTvvumPQ812dlPgibN1QOU3rt" +
"6dvAT48ahYsnZLnu2sgLao2l/wKqtL6U4HHHBxj95yJ83v7DFgChxVusFvTeneqKt4JMHseDuBjf4AXwQKP2hyscemwxpmw" +
"bBuuNhyoj0bT9rfnu1Y+TsqK8FFY4p5qBkE05siEoztGKJVbCGIjtHsitWb1nZPHqFut/NXTFMWbwgntQctIwF71yWt62Pu" +
"simk541NdCbpNnU5ArtR482QYwMU9KtBJyqeNstmiyupwuvALp7ww3fIhILoOfL01cjvz74SgOUsa9+Aqkh64D/53Z/Zgfe" +
"BcrwRQc5gMbC4kVZY2DDGlmYlB9PPTduofaq/l8FcvvWLFehPFvh5Mox8ZQdtlPxrRRRUmDGFAgMBAAGjgfUwgfIwHwYDVR" +
"0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwO" +
"i8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NB" +
"MTEvUlNBL2NybDI2NjU1LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFBl1Gmb89bqbEKyFcTU3eOY/5NmKMB0GA1UdJQQ" +
"WMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEADEU//9rnWN1s3/ariMHIUmgzRUdz3fWYiDRzGC" +
"mcnnETlXDstGmoYmwCM+QwHw6cyKXkwkg9zV7c7CgM471ZuF00gq115d432Ps3RXGCpfQ2fn3gs+91ky/YqJOOyBb8KL0IP" +
"r/Zh56/y3XX0gORn4GLqaj+oVZrFcmKrPtVhySlXNiD5BRMq39mUbuLBweGsgNVQ9VxiWc8ZBGjlJ6OVsngbvWrtl3zgkKb" +
"X9lhr8Bxq3G+jOV8jvr1Dkn4a65g2TWcFquxmPvRc5UwN29CimbC7RViCL3Jp+zrGasqbjycuqu5eSXb6gG4/aV0/K9yn5k" +
"YlZMIBlbsXSEi5J26pg==";

String issuerCert =
"-----BEGIN CERTIFICATE-----\n" +
"MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" +
"VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" +
"QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" +
"NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" +
"bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" +
"RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" +
"jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" +
"jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" +
"bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" +
"RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" +
"0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" +
"t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" +
"aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" +
"Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" +
"MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" +
"AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" +
"3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" +
"/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" +
"/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" +
"fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" +
"OMRZvB7FRyE9IfwKApngcZbA5g==\n" +
"-----END CERTIFICATE-----";

byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr);
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr);

CSRBuilder builder = new CSRBuilder();
builder.init("SHA1withRSA", rawPublicKeyBytes, rawPrivateKeyBytes);

String csr = builder.buildRequest(countryName,stateName,cityName,
organizationName,departmentName,domainName,
emailName);

assertEquals(expectedCSR,csr);

CertParser parser = new CertParser();
parser.parse(expectedUserCert,issuerCert);

PublicKey rawPublicKeyInCert = parser.getPubKey();
// check that the public key in inputs and the public key in certificate are consistent
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded());

String algoName = parser.getSigAlgName();
int keyLength = parser.getKeyLength();
String length = String.valueOf(keyLength);
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase());

CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo);
assertNotNull(algorithm);
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);

PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes);
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes);

// signTest
byte[] data = new byte[1024];
Random random = new Random();
random.nextBytes(data);

SignatureDigest signature = signatureFunction.sign(privKey, data);
assertTrue(signatureFunction.verify(signature, pubKey, data));
}
}

+ 80
- 0
source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunctionTest.java View File

@@ -1,9 +1,13 @@
package com.jd.blockchain.crypto.service.pki;

import com.jd.blockchain.crypto.*;
import com.jd.blockchain.crypto.utils.CSRBuilder;
import com.jd.blockchain.crypto.utils.CertParser;
import com.jd.blockchain.utils.io.BytesUtils;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

import java.security.PublicKey;
import java.util.Random;

import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY;
@@ -270,4 +274,80 @@ public class SM3WITHSM2SignatureFunctionTest {
resolvedSignatureDigest.getAlgorithm());
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
}


@Test
public void testWithCSRAndCert() {

String publicKeyStr = "3059301306072a8648ce3d020106082a811ccf5501822d03420004aa6586478be879504fdd02892f" +
"b4cf2bdb3d96a316f41ff7bcadfabef4ea836678984f9ba6931a609391426ca7164592f5fccd062be56fc32b3eec3a5" +
"0400971";

String privateKeyStr = "308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104207abd2953" +
"84f193abe4f3715c26bc15225061f007131755d94ca12c7e0ce0b3a0a00a06082a811ccf5501822da14403420004aa6" +
"586478be879504fdd02892fb4cf2bdb3d96a316f41ff7bcadfabef4ea836678984f9ba6931a609391426ca7164592f5" +
"fccd062be56fc32b3eec3a50400971";

String expectedUserCert = "MIICwjCCAmWgAwIBAgIFIChnMlIwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UEC" +
"gwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTEx" +
"MB4XDTE5MDgyODA4MTUzNloXDTIxMDgyODA4MTUzNloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0E" +
"xMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMT" +
"g2MTIyMjkyOTVAODBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABKplhkeL6HlQT90CiS+0zyvbPZajFvQf97yt+r706oNme" +
"JhPm6aTGmCTkUJspxZFkvX8zQYr5W/DKz7sOlBACXGjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8w" +
"SAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh" +
"0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDI0OTkuY3JsMAsGA1UdDwQEAw" +
"ID6DAdBgNVHQ4EFgQU07tMtbs5PWkwN33OQVH116xd1kowHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBH" +
"M9VAYN1BQADSQAwRgIhAPuuInppVhugw6EIG4wgkouxX/MX2dTLe478wx7LFXSQAiEAneiz51vrurICNCfeecaBHgzaj7+3" +
"kmrdIZJBoxYGbso=";

String issuerCert =
"-----BEGIN CERTIFICATE-----\n" +
"MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" +
"BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" +
"dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" +
"MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" +
"Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" +
"DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" +
"L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" +
"9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" +
"w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" +
"MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" +
"VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" +
"AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" +
"PrIDl+E4aL3FypntFXHG3T+Keg==\n" +
"-----END CERTIFICATE-----";

byte[] rawPublicKeyBytes = Hex.decode(publicKeyStr);
byte[] rawPrivateKeyBytes = Hex.decode(privateKeyStr);

CSRBuilder builder = new CSRBuilder();
builder.init("SM3withSM2", rawPublicKeyBytes, rawPrivateKeyBytes);

CertParser parser = new CertParser();
parser.parse(expectedUserCert,issuerCert);

PublicKey rawPublicKeyInCert = parser.getPubKey();
// check that the public key in inputs and the public key in certificate are consistent
assertArrayEquals(rawPublicKeyBytes, rawPublicKeyInCert.getEncoded());

String algoName = parser.getSigAlgName();
int keyLength = parser.getKeyLength();
String length = String.valueOf(keyLength);
String algo = (algoName.contains("RSA")? (algoName + length).toUpperCase(): algoName.toUpperCase());

CryptoAlgorithm algorithm = Crypto.getAlgorithm(algo);
assertNotNull(algorithm);
SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);

PubKey pubKey = new PubKey(algorithm, rawPublicKeyBytes);
PrivKey privKey = new PrivKey(algorithm, rawPrivateKeyBytes);

// signTest
byte[] data = new byte[1024];
Random random = new Random();
random.nextBytes(data);

SignatureDigest signature = signatureFunction.sign(privKey, data);
assertTrue(signatureFunction.verify(signature, pubKey, data));
}
}

+ 8
- 4
source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CertParserTest.java View File

@@ -43,7 +43,8 @@ public class CertParserTest {
String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW";

parser.parse(userCert, issuerCert);
assertEquals("SHA1WITHRSA",parser.getSigAlgName());
assertEquals("SHA1WITHRSA", parser.getSigAlgName());
assertEquals(2048, parser.getKeyLength());
}

@Test
@@ -77,7 +78,8 @@ public class CertParserTest {
String userCert = "MIIFRjCCBC6gAwIBAgIFICdWiDMwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxNjA3MDcyMloXDTIxMDUxNjA3MDcyMloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL0rTOxd8rsjPtFJ0aGVh9bZPy5Xo0SADaP7BbJsG4+ykLQMZHg9hTf/6fv1OsD2HEKFoMpIkW2gwCJW2nvicHcVql/shCoktc6ZBW6Dr/DxOgbO9tpoGxZ50xdI4Q0NsrxqtbCldW4ozPHdjgRJ83i1KSFh7evNrVByN/mB+jchrVGLWyJ1uIRgUUgpRZmZPoOHaizVJqrqWJGGk6xbDLR2gUQ1hTzetQaz1OeKtelHDk9FY08XSmNGssSMpuSjrxn78S888VW5WIxyo4cwrXSXFk3J7LNTy70Oga16HZjJD/vLTM6a4riPa8+uivPinKxK38/++nlBPNwhx6n46uYkd9Zvw+SJiJgpnuPJLtMZpKpJx7V1BDVEydKPUthilTdsmJtkBFSlFw0G1aKfuciBGzzJ3SKngJF/JqJAWIonVAFBGb6Gokp1Sw+T4KqXrdbjxYxiyyjZ++8O1vydgFAkx/NjsuwJnpKETiRKFJmY7YawcUvC4ixF7XQc0luFWRDYcbxOppir+ieMqhGXyaFhLUuB4WXv+rFxfa3NmkBW8q5TPzt/PwWcXpITsYTZYla/E/grB+OeZLYgjigT5YlgytPHG6Gt1ySCCd8WXFWpkBbQfXzqcvtU27RCcAUgfXk5NLb7NZCQg7heGjgzOdYJCPsa1d3m7l04+VIKGCZdAgMBAAGjgfUwgfIwHwYDVR0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvUlNBL2NybDI1NzE3LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFMjh6AzDCuNkD+pqQfiS6bqPGpI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEApZaLXS6/6FudPA3l2xom5U7nJUOpQ1E6DO/ic9dFGtLE0WgyAqB3JVPvXEntppX55x/dAV7rvvz9NaEdiAe8DAj7qyoPDvC8ZWQK8U4n9l8N78QwALOURxzQNs+CBatJQzbu2w1RKVwkfE6xEIVnu+wjiAtymfwdLHMagHxDIC/eOPbTnbbtITJk2ukFfoc0WJ6Awg5lW+x7nGokEn/XAjKyRHCpkRUFGQm4ww41zlrqCqQqnVGVABJtjbdtFf7nh33QHl0fkj19nfMox9eGuntPyM0bNA0XqPMA+FWSCqeDT6uLbyaOKWxlhv53U/NCJl76U3tssMEWsm9amEDDQg==";

parser.parse(userCert, issuerCert);
assertEquals("SHA1WITHRSA",parser.getSigAlgName());
assertEquals("SHA1WITHRSA", parser.getSigAlgName());
assertEquals(4096, parser.getKeyLength());
}

@Test
@@ -103,7 +105,8 @@ public class CertParserTest {
String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq";

parser.parse(userCert, issuerCert);
assertEquals("SM3WITHSM2",parser.getSigAlgName());
assertEquals("SM3WITHSM2", parser.getSigAlgName());
assertEquals(256, parser.getKeyLength());
}

@Test
@@ -141,6 +144,7 @@ public class CertParserTest {
"PrIDl+E4aL3FypntFXHG3T+Keg==\n" +
"-----END CERTIFICATE-----";
parser.parse(issuerCert, CACert);
assertEquals("SM3WITHSM2",parser.getSigAlgName());
assertEquals("SM3WITHSM2", parser.getSigAlgName());
assertEquals(256, parser.getKeyLength());
}
}

+ 6
- 13
source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java View File

@@ -13,6 +13,8 @@ import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.*;

import java.io.IOException;
@@ -29,19 +31,10 @@ public class SM2Utils {
// The length of sm3 output is 32 bytes
private static final int SM3DIGEST_LENGTH = 32;

private static final BigInteger SM2_P = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
private static final BigInteger SM2_A = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
private static final BigInteger SM2_B = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
private static final BigInteger SM2_N = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
private static final BigInteger SM2_H = ECConstants.ONE;
private static final BigInteger SM2_GX = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
private static final BigInteger SM2_GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);

// To get the curve from the equation y^2=x^3+ax+b according the coefficient a and b,
// with the big prime p, the order n, the cofactor h, and obtain the generator g and the domain's parameters
private static final ECCurve CURVE = new ECCurve.Fp(SM2_P, SM2_A, SM2_B, SM2_N, SM2_H);
private static final ECPoint G = CURVE.createPoint(SM2_GX, SM2_GY);
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G, SM2_N);
private static final ECNamedCurveParameterSpec PARAMS = ECNamedCurveTable.getParameterSpec("sm2p256v1");
private static final ECCurve CURVE = PARAMS.getCurve();
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(
CURVE, PARAMS.getG(), PARAMS.getN(), PARAMS.getH());


//-----------------Key Generation Algorithm-----------------


+ 0
- 0
source/deployment/deployment-gateway/conf/application-gw.properties View File


+ 6
- 4
source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java View File

@@ -18,15 +18,13 @@ public class GatewayBooter {
writePID();
GatewayServerBooter.main(args);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage());
}
}

private static final void writePID() throws Exception {
URL url = GatewayBooter.class
.getProtectionDomain()
.getCodeSource()
.getLocation();
URL url = GatewayBooter.class.getProtectionDomain().getCodeSource().getLocation();
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8");
if (currPath.contains("!/")) {
currPath = currPath.substring(5, currPath.indexOf("!/"));
@@ -40,6 +38,10 @@ public class GatewayBooter {
String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log";
File pidFile = new File(pidFilePath);
if (!pidFile.exists()) {
File dir = pidFile.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
}
pidFile.createNewFile();
}
String name = ManagementFactory.getRuntimeMXBean().getName();


+ 2
- 2
source/deployment/deployment-peer/pom.xml View File

@@ -25,11 +25,11 @@
<artifactId>runtime-modular-booter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<!--<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>ump-booter</artifactId>
<version>${project.version}</version>
</dependency>
</dependency>-->
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>storage-composite</artifactId>


+ 2
- 2
source/deployment/deployment-peer/src/main/resources/assembly.xml View File

@@ -61,14 +61,14 @@
</excludes>
</dependencySet>

<dependencySet>
<!--<dependencySet>
<unpack>false</unpack>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>ext</outputDirectory>
<includes>
<include>com.jd.blockchain:ump-booter</include>
</includes>
</dependencySet>
</dependencySet>-->

</dependencySets>



+ 1
- 1
source/deployment/deployment-peer/src/main/resources/scripts/startup.sh View File

@@ -5,5 +5,5 @@ PEER=$(ls $HOME/system | grep deployment-peer-)
if [ ! -n "$PEER" ]; then
echo "Peer Is Null !!!"
else
nohup java -jar -server -Xmx768m -Xms512m -Dpeer.log=$HOME $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* >$HOME/bin/peer.out 2>&1 &
nohup java -jar -server -Xmx2g -Xms2g -Dpeer.log=$HOME $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* >$HOME/bin/peer.out 2>&1 &
fi

+ 1
- 19
source/gateway/pom.xml View File

@@ -75,24 +75,6 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>

<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-core</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-expressions</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-reflection</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-compilertools</artifactId>
</dependency>

<dependency>
@@ -110,7 +92,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>


+ 7
- 7
source/gateway/src/main/java/com/jd/blockchain/gateway/GatewayServerBooter.java View File

@@ -5,20 +5,20 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.jd.blockchain.gateway.web.BlockBrowserController;
import org.apache.commons.io.FileUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.ClassPathResource;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.KeyGenUtils;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.gateway.web.BlockBrowserController;
import com.jd.blockchain.utils.ArgumentSet;
import com.jd.blockchain.utils.ArgumentSet.ArgEntry;
import com.jd.blockchain.utils.BaseConstant;
import com.jd.blockchain.utils.ConsoleUtils;
import com.jd.blockchain.utils.ArgumentSet.ArgEntry;
public class GatewayServerBooter {
@@ -88,19 +88,19 @@ public class GatewayServerBooter {
String base58Pwd = config.keys().getDefault().getPrivKeyPassword();
if (base58Pwd == null || base58Pwd.length() == 0) {
base58Pwd = KeyGenCommand.readPasswordString();
base58Pwd = KeyGenUtils.readPasswordString();
}
// 加载密钥;
PubKey pubKey = KeyGenCommand.decodePubKey(config.keys().getDefault().getPubKeyValue());
PubKey pubKey = KeyGenUtils.decodePubKey(config.keys().getDefault().getPubKeyValue());
PrivKey privKey = null;
String base58PrivKey = config.keys().getDefault().getPrivKeyValue();
if (base58PrivKey == null) {
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一;
privKey = KeyGenCommand.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd);
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd);
} else {
privKey = KeyGenCommand.decodePrivKey(base58PrivKey, base58Pwd);
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd);
}
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey);
}


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

@@ -0,0 +1,8 @@
package com.jd.blockchain.gateway.service;

import com.jd.blockchain.ledger.TransactionRequest;

public interface GatewayInterceptService {

void intercept(TransactionRequest txRequest);
}

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

@@ -0,0 +1,35 @@
package com.jd.blockchain.gateway.service;

import com.jd.blockchain.contract.ContractJarUtils;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GatewayInterceptServiceHandler implements GatewayInterceptService {

@Autowired
private PeerService peerService;

@Override
public void intercept(TransactionRequest txRequest) {
// 当前仅处理合约发布的请求
Operation[] operations = txRequest.getTransactionContent().getOperations();
if (operations != null && operations.length > 0) {
for (Operation op : operations) {
if (ContractCodeDeployOperation.class.isAssignableFrom(op.getClass())) {
// 发布合约请求
contractCheck((ContractCodeDeployOperation)op);
}
}
}
}

private void contractCheck(final ContractCodeDeployOperation contractOP) {
// 校验chainCode
ContractJarUtils.verify(contractOP.getChainCode());
}
}

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

@@ -4,7 +4,6 @@ import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.sdk.ContractSettings;
import com.jd.blockchain.sdk.LedgerInitSettings;
import com.jd.blockchain.utils.Bytes;

/**
* queryService only for gateway;


+ 13
- 12
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java View File

@@ -3,18 +3,17 @@ package com.jd.blockchain.gateway.service;
import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider;
import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.gateway.PeerService;
import com.jd.blockchain.gateway.decompiler.utils.DecompilerUtils;
import com.jd.blockchain.ledger.ContractInfo;
import com.jd.blockchain.ledger.LedgerAdminInfo;
import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.sdk.ContractSettings;
import com.jd.blockchain.sdk.LedgerInitSettings;
import com.jd.blockchain.utils.QueryUtil;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.decompiler.utils.DecompilerUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@@ -53,7 +52,9 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {

LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash);

return initLedgerInitSettings(participantNodes, ledgerMetadata);
LedgerAdminInfo ledgerAdminInfo = peerService.getQueryService().getLedgerAdminInfo(ledgerHash);

return initLedgerInitSettings(participantNodes, ledgerMetadata, ledgerAdminInfo);
}

@Override
@@ -80,26 +81,26 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {
* 账本元数据
* @return
*/
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata) {
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata, LedgerAdminInfo ledgerAdminInfo) {
LedgerInitSettings ledgerInitSettings = new LedgerInitSettings();

// 设置参与方
ledgerInitSettings.setParticipantNodes(participantNodes);

// 设置共识设置
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerMetadata));
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerAdminInfo));

// 设置参与方根Hash
ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash());

// 设置算法配置
ledgerInitSettings.setCryptoSetting(ledgerMetadata.getSetting().getCryptoSetting());
ledgerInitSettings.setCryptoSetting(ledgerAdminInfo.getSettings().getCryptoSetting());

// 设置种子
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed()));

// 设置共识协议
ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider());
ledgerInitSettings.setConsensusProtocol(ledgerAdminInfo.getSettings().getConsensusProvider());

return ledgerInitSettings;
}
@@ -131,14 +132,14 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {
/**
* 初始化共识配置
*
* @param ledgerMetadata
* @param ledgerAdminInfo
* 账本元数据
* @return
*/
private ConsensusSettings initConsensusSettings(LedgerMetadata ledgerMetadata) {
String consensusProvider = ledgerMetadata.getSetting().getConsensusProvider();
private ConsensusSettings initConsensusSettings(LedgerAdminInfo ledgerAdminInfo) {
String consensusProvider = ledgerAdminInfo.getSettings().getConsensusProvider();
ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider);
byte[] consensusSettingsBytes = ledgerMetadata.getSetting().getConsensusSetting().toBytes();
byte[] consensusSettingsBytes = ledgerAdminInfo.getSettings().getConsensusSetting().toBytes();
return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes);
}
}

+ 551
- 549
source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
File diff suppressed because it is too large
View File


+ 1
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java View File

@@ -35,6 +35,7 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer {
JSONSerializeUtils.disableCircularReferenceDetect();
JSONSerializeUtils.configStringSerializer(ByteArray.class);
DataContractRegistry.register(BftsmartNodeSettings.class);
// DataContractRegistry.register(LedgerAdminInfo.class);
}




+ 7
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/web/TxProcessingController.java View File

@@ -1,6 +1,7 @@
package com.jd.blockchain.gateway.web;

import com.jd.blockchain.crypto.*;
import com.jd.blockchain.gateway.service.GatewayInterceptService;
import com.jd.blockchain.transaction.SignatureUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
@@ -29,9 +30,15 @@ public class TxProcessingController implements TransactionService {
@Autowired
private PeerService peerService;

@Autowired
private GatewayInterceptService interceptService;

@RequestMapping(path = "rpc/tx", method = RequestMethod.POST, consumes = BinaryMessageConverter.CONTENT_TYPE_VALUE, produces = BinaryMessageConverter.CONTENT_TYPE_VALUE)
@Override
public @ResponseBody TransactionResponse process(@RequestBody TransactionRequest txRequest) {
// 拦截请求进行校验
interceptService.intercept(txRequest);

// 检查交易请求的信息是否完整;
HashDigest ledgerHash = txRequest.getTransactionContent().getLedgerHash();
if (ledgerHash == null) {


+ 5
- 0
source/ledger/ledger-core/pom.xml View File

@@ -40,6 +40,11 @@
<artifactId>contract-framework</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>consensus-framework</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-jvm</artifactId>


+ 0
- 26
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountPrivilege.java View File

@@ -1,26 +0,0 @@
package com.jd.blockchain.ledger.core;

public interface AccountPrivilege {

/**
* 数据“读”的操作码;
*
* @return
*/
byte getReadingOpCode();

/**
* “写”的操作码;
*
* @return
*/
byte getWrittingOpCode();

/**
* 其它的扩展操作码;
*
* @return
*/
byte[] getExtOpCodes();

}

+ 5
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java View File

@@ -12,6 +12,7 @@ import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
@@ -48,6 +49,10 @@ public class AccountSet implements Transactional, MerkleProvable {
public boolean isReadonly() {
return merkleDataset.isReadonly();
}
void setReadonly() {
merkleDataset.setReadonly();
}
public AccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage,
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) {
@@ -65,10 +70,6 @@ public class AccountSet implements Transactional, MerkleProvable {
this.accessPolicy = accessPolicy;
}
// public HashDigest getAccountRootHash() {
// return merkleDataset.getRootHash();
// }
@Override
public HashDigest getRootHash() {
return merkleDataset.getRootHash();


+ 0
- 168
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AuthorizableDataSet.java View File

@@ -1,168 +0,0 @@
//package com.jd.blockchain.ledger.core;
//
//import com.jd.blockchain.crypto.hash.HashDigest;
//
//import my.utils.Scratchable;
//import my.utils.io.ByteArray;
//import my.utils.io.BytesUtils;
//import my.utils.io.ExistancePolicyKVStorage;
//import my.utils.io.VersioningKVStorage;
//
///**
// * 可进行授权控制的数据集合;
// *
// * @author huanghaiquan
// *
// */
//public class AuthorizableDataSet implements Scratchable {
//
// public static final String DATA_PREFIX = "DATA" + LedgerConsts.KEY_SEPERATOR;
//// public static final String PRIVILEGE_PREFIX = "PRVL" + LedgerConsts.KEY_SEPERATOR;
//
// private static final String DEFAULT_PRIVILEGE_KEY = "%";
//
// private DataAccessable accessable;
//
// protected MerkleDataSet data;
//
//// private PrivilegeDataSet privileges;
//
// /**
// * Create a new Account instance;
// *
// * @param address
// * @param pubKey
// */
// protected AuthorizableDataSet(CryptoSetting merkleTreeSetting, ExistancePolicyKVStorage simpleStorage,
// VersioningKVStorage versioningStorage) {
// this(null, merkleTreeSetting, null, simpleStorage, versioningStorage);
// }
//
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash,
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage) {
// this(dataRootHash, merkleTreeSetting, privilegeRootHash, simpleStorage, versioningStorage, false);
// }
//
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash,
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage, boolean readonly) {
// this.data = new MerkleDataSet(dataRootHash, merkleTreeSetting,
// PrefixAppender.prefix(DATA_PREFIX, simpleStorage),
// PrefixAppender.prefix(DATA_PREFIX, versioningStorage), readonly);
//
//// this.privileges = new PrivilegeDataSet(privilegeRootHash, merkleTreeSetting,
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, simpleStorage),
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, versioningStorage), readonly);
// }
//
// public ByteArray getDataRootHash() {
// return data.getRootHash();
// }
//
//// public ByteArray getPrivilegeRootHash() {
//// return privileges.getRootHash();
//// }
//
// /**
// *
// * @param userAddress
// * @param op
// * @param enable
// */
// public void setPrivilege(String userAddress, byte op, boolean enable) {
//
// }
//
// /**
// *
// * @param op
// * @param enable
// */
// public void setDefaultPrivilege(byte op, boolean enable) {
// }
//
// public boolean checkCurrentUserPrivilege() {
// return false;
// }
//
// /**
// * Return the latest version entry associated the specified key; If the key
// * doesn't exist, then return -1;
// *
// * @param key
// * @return
// */
// public long getVersion(String key) {
// return data.getVersion(key);
// }
//
// protected long setString(String key, String value, long version) {
// checkWritting();
// byte[] bytes = BytesUtils.toBytes(value, LedgerConsts.CHARSET);
// return data.setValue(key, bytes, version);
// }
//
// protected String getString(String key) {
// checkReading();
// byte[] value = data.getValue(key);
// return BytesUtils.toString(value, LedgerConsts.CHARSET);
// }
//
// protected String getString(String key, long version) {
// checkReading();
// byte[] value = data.getValue(key, version);
// return BytesUtils.toString(value, LedgerConsts.CHARSET);
// }
//
// protected long setValue(String key, byte[] value, long version) {
// checkWritting();
// return data.setValue(key, value, version);
// }
//
// protected byte[] getValue(String key) {
// checkReading();
// return data.getValue(key);
// }
//
// protected byte[] getValue(String key, long version) {
// checkReading();
// return data.getValue(key, version);
// }
//
// private void checkWritting() {
// // Check writting enable;
// }
//
// private void checkReading() {
// // TODO Check privilege of reading;
// }
//
// // /**
// // * 数据“读”的操作码;
// // *
// // * @return
// // */
// // protected abstract AccountPrivilege getPrivilege();
//
// @Override
// public boolean isUpdated() {
// return data.isUpdated();
//// return data.isUpdated()|| privileges.isUpdated();
// }
//
// @Override
// public void commit() {
// if (data.isUpdated()) {
// data.commit();
// }
//// if (privileges.isUpdated()) {
//// privileges.commit();
//// }
// }
//
// @Override
// public void cancel() {
// data.cancel();
//// privileges.cancel();
// }
//
//}

+ 0
- 40
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Authorization.java View File

@@ -1,40 +0,0 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.DigitalSignature;

/**
* {@link Authorization} 抽象了对特定用户/角色的授权信息;
*
* @author huanghaiquan
*
*/
public interface Authorization {

/**
* 被授权用户/角色的地址;
*
* @return
*/
String getAddress();

/**
* 授权码;<br>
*
* @return
*/
byte[] getCode();

/**
* 授权者的签名;
*
* @return
*/
DigitalSignature getSignature();

// /**
// * 授权生成的时间戳;
// * @return
// */
// long getTs();

}

+ 0
- 42
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AuthorizationVO.java View File

@@ -1,42 +0,0 @@
package com.jd.blockchain.ledger.core;
import com.jd.blockchain.ledger.DigitalSignature;
public class AuthorizationVO implements Authorization {
private String address;
private byte[] code;
private DigitalSignature signature;
@Override
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public byte[] getCode() {
return code;
}
public void setCode(byte[] code) {
this.code = code;
}
@Override
public DigitalSignature getSignature() {
return signature;
}
public void setSignature(DigitalSignature signature) {
this.signature = signature;
}
}

+ 4
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/BaseAccount.java View File

@@ -8,6 +8,7 @@ import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BlockchainIdentityData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
@@ -64,13 +65,13 @@ public class BaseAccount implements AccountHeader, MerkleProvable, Transactional

/**
* Create a account instance with the specified address and pubkey and load it's
* merkle dataset with the specified root hash. which is used for storing data
* merkle dataset from the specified root hash. This merkle dateset is used for storing data
* of this account.<br>
*
* @param address
* @param pubKey
* @param dataRootHash merkle root hash of account's data; if null be set,
* create a new empty merkle dataset;
* @param dataRootHash merkle root hash of account's data; if set to a null value,
* an empty merkle dataset is created;
* @param cryptoSetting
* @param exStorage
* @param verStorage


+ 0
- 21
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Consensus.java View File

@@ -1,21 +0,0 @@
package com.jd.blockchain.ledger.core;
/**
* @author hhq
* @version 1.0
* @created 14-6��-2018 12:13:32
*/
public class Consensus {
public P2PRealm m_P2PRealm;
public Consensus(){
}
public void finalize() throws Throwable {
}
}

+ 2
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java View File

@@ -2,10 +2,10 @@ package com.jd.blockchain.ledger.core;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.ContractInfo;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.utils.Bytes;
public class ContractAccount implements ContractInfo {


+ 29
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountQuery.java View File

@@ -0,0 +1,29 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.utils.Bytes;

public interface ContractAccountQuery {

AccountHeader[] getAccounts(int fromIndex, int count);

HashDigest getRootHash();

/**
* 返回合约总数;
*
* @return
*/
long getTotalCount();

MerkleProof getProof(Bytes address);

boolean contains(Bytes address);

ContractAccount getContract(Bytes address);

ContractAccount getContract(Bytes address, long version);

}

+ 11
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccountSet.java View File

@@ -5,12 +5,13 @@ import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
public class ContractAccountSet implements MerkleProvable, Transactional {
public class ContractAccountSet implements MerkleProvable, Transactional, ContractAccountQuery {
private AccountSet accountSet;
@@ -25,6 +26,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional {
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy);
}
@Override
public AccountHeader[] getAccounts(int fromIndex, int count) {
return accountSet.getAccounts(fromIndex,count);
}
@@ -33,6 +35,10 @@ public class ContractAccountSet implements MerkleProvable, Transactional {
return accountSet.isReadonly();
}
void setReadonly() {
accountSet.setReadonly();
}
@Override
public HashDigest getRootHash() {
return accountSet.getRootHash();
@@ -43,6 +49,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional {
*
* @return
*/
@Override
public long getTotalCount() {
return accountSet.getTotalCount();
}
@@ -52,15 +59,18 @@ public class ContractAccountSet implements MerkleProvable, Transactional {
return accountSet.getProof(address);
}
@Override
public boolean contains(Bytes address) {
return accountSet.contains(address);
}
@Override
public ContractAccount getContract(Bytes address) {
BaseAccount accBase = accountSet.getAccount(address);
return new ContractAccount(accBase);
}
@Override
public ContractAccount getContract(Bytes address, long version) {
BaseAccount accBase = accountSet.getAccount(address, version);
return new ContractAccount(accBase);


+ 1
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/CryptoConfig.java View File

@@ -82,7 +82,7 @@ public class CryptoConfig implements CryptoSetting {

public void setHashAlgorithm(short hashAlgorithm) {
if (codeAlgorithms == null || !codeAlgorithms.containsKey(hashAlgorithm)) {
throw new LedgerException("The specified algorithm[" + hashAlgorithm + "] has no provider!");
throw new LedgerException("Current CryptoConfig has no crypto provider!");
}
this.hashAlgorithm = hashAlgorithm;
}


+ 95
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java View File

@@ -1,14 +1,14 @@
package com.jd.blockchain.ledger.core;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.KVDataObject;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.utils.Bytes;
public class DataAccount implements AccountHeader, MerkleProvable {
@@ -43,16 +43,85 @@ public class DataAccount implements AccountHeader, MerkleProvable {
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, BytesValue value, long version) {
return baseAccount.setBytes(key, value, version);
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, String value, long version) {
BytesValue bytesValue = BytesData.fromText(value);
return baseAccount.setBytes(key, bytesValue, version);
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, byte[] value, long version) {
BytesValue bytesValue = BytesData.fromBytes(value);
return baseAccount.setBytes(key, bytesValue, version);
@@ -121,6 +190,29 @@ public class DataAccount implements AccountHeader, MerkleProvable {
public BytesValue getBytes(Bytes key, long version) {
return baseAccount.getBytes(key, version);
}
/**
* @param key
* @param version
* @return
*/
public KVDataEntry getDataEntry(String key, long version) {
return getDataEntry(Bytes.fromString(key), version);
}
/**
* @param key
* @param version
* @return
*/
public KVDataEntry getDataEntry(Bytes key, long version) {
BytesValue value = baseAccount.getBytes(key, version);
if (value == null) {
return new KVDataObject(key.toUTF8String(), -1, null);
}else {
return new KVDataObject(key.toUTF8String(), version, value);
}
}
/**
* return the specified index's KVDataEntry;
@@ -131,7 +223,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
*/
public KVDataEntry[] getDataEntries(int fromIndex, int count) {
if (getDataEntriesTotalCount() == 0 || count == 0) {
if (count == 0 || getDataEntriesTotalCount() == 0) {
return null;
}


+ 32
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountQuery.java View File

@@ -0,0 +1,32 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.utils.Bytes;

public interface DataAccountQuery {

AccountHeader[] getAccounts(int fromIndex, int count);

HashDigest getRootHash();

long getTotalCount();

/**
* 返回账户的存在性证明;
*/
MerkleProof getProof(Bytes address);

/**
* 返回数据账户; <br>
* 如果不存在,则返回 null;
*
* @param address
* @return
*/
DataAccount getDataAccount(Bytes address);

DataAccount getDataAccount(Bytes address, long version);

}

+ 10
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java View File

@@ -5,12 +5,13 @@ import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
public class DataAccountSet implements MerkleProvable, Transactional {
public class DataAccountSet implements MerkleProvable, Transactional, DataAccountQuery {
private AccountSet accountSet;
@@ -25,6 +26,7 @@ public class DataAccountSet implements MerkleProvable, Transactional {
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy);
}
@Override
public AccountHeader[] getAccounts(int fromIndex, int count) {
return accountSet.getAccounts(fromIndex, count);
}
@@ -33,11 +35,16 @@ public class DataAccountSet implements MerkleProvable, Transactional {
return accountSet.isReadonly();
}
void setReadonly() {
accountSet.setReadonly();
}
@Override
public HashDigest getRootHash() {
return accountSet.getRootHash();
}
@Override
public long getTotalCount() {
return accountSet.getTotalCount();
}
@@ -63,6 +70,7 @@ public class DataAccountSet implements MerkleProvable, Transactional {
* @param address
* @return
*/
@Override
public DataAccount getDataAccount(Bytes address) {
BaseAccount accBase = accountSet.getAccount(address);
if (accBase == null) {
@@ -71,6 +79,7 @@ public class DataAccountSet implements MerkleProvable, Transactional {
return new DataAccount(accBase);
}
@Override
public DataAccount getDataAccount(Bytes address, long version) {
BaseAccount accBase = accountSet.getAccount(address, version);
return new DataAccount(accBase);


+ 122
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DefaultOperationHandleRegisteration.java View File

@@ -0,0 +1,122 @@
package com.jd.blockchain.ledger.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.stereotype.Component;

import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.core.handles.ContractCodeDeployOperationHandle;
import com.jd.blockchain.ledger.core.handles.DataAccountKVSetOperationHandle;
import com.jd.blockchain.ledger.core.handles.DataAccountRegisterOperationHandle;
import com.jd.blockchain.ledger.core.handles.JVMContractEventSendOperationHandle;
import com.jd.blockchain.ledger.core.handles.LedgerInitOperationHandle;
import com.jd.blockchain.ledger.core.handles.ParticipantRegisterOperationHandle;
import com.jd.blockchain.ledger.core.handles.ParticipantStateUpdateOperationHandle;
import com.jd.blockchain.ledger.core.handles.RolesConfigureOperationHandle;
import com.jd.blockchain.ledger.core.handles.UserAuthorizeOperationHandle;
import com.jd.blockchain.ledger.core.handles.UserRegisterOperationHandle;

@Component
public class DefaultOperationHandleRegisteration implements OperationHandleRegisteration {

private static Map<Class<?>, OperationHandle> DEFAULT_HANDLES = new HashMap<>();

private Map<Class<?>, OperationHandle> handles = new ConcurrentHashMap<>();

static {
registerDefaultHandle(new LedgerInitOperationHandle());

registerDefaultHandle(new RolesConfigureOperationHandle());

registerDefaultHandle(new UserAuthorizeOperationHandle());

registerDefaultHandle(new UserRegisterOperationHandle());

registerDefaultHandle(new DataAccountKVSetOperationHandle());

registerDefaultHandle(new DataAccountRegisterOperationHandle());

registerDefaultHandle(new ContractCodeDeployOperationHandle());

registerDefaultHandle(new JVMContractEventSendOperationHandle());

registerDefaultHandle(new ParticipantRegisterOperationHandle());

registerDefaultHandle(new ParticipantStateUpdateOperationHandle());
}

private static void registerDefaultHandle(OperationHandle handle) {
DEFAULT_HANDLES.put(handle.getOperationType(), handle);
}

/**
* 注册操作处理器;此方法将覆盖默认的操作处理器配置;
*
* @param handle
*/
public void registerHandle(OperationHandle handle) {
List<Class<?>> opTypes = new ArrayList<Class<?>>();
for (Class<?> opType : handles.keySet()) {
if (opType.isAssignableFrom(handle.getOperationType())) {
opTypes.add(opType);
}
}

for (Class<?> opType : opTypes) {
handles.put(opType, handle);
}
handles.put(handle.getOperationType(), handle);
}

private OperationHandle getRegisteredHandle(Class<?> operationType) {
OperationHandle hdl = handles.get(operationType);
if (hdl == null) {
hdl = DEFAULT_HANDLES.get(operationType);
//按“操作类型”的继承关系匹配;
if (hdl == null) {
for (Class<?> opType : handles.keySet()) {
if (opType.isAssignableFrom(operationType)) {
hdl = handles.get(opType);
break;
}
}
}
if (hdl == null) {
for (Class<?> opType : DEFAULT_HANDLES.keySet()) {
if (opType.isAssignableFrom(operationType)) {
hdl = DEFAULT_HANDLES.get(opType);
break;
}
}
}
if (hdl != null) {
handles.put(operationType, hdl);
}
}
return hdl;
}

/*
* (non-Javadoc)
*
* @see
* com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration#getHandle(
* java.lang.Class)
*/
@Override
public OperationHandle getHandle(Class<? extends Operation> operationType) {
OperationHandle hdl = getRegisteredHandle(operationType);
if (hdl == null) {
throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!");
}
return hdl;
}
}

+ 209
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/EmptyLedgerDataset.java View File

@@ -0,0 +1,209 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.LedgerAdminInfo;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.ledger.ParticipantDataQuery;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.utils.Bytes;

public class EmptyLedgerDataset implements LedgerDataQuery {
private static final LedgerAdminDataQuery EMPTY_ADMIN_DATA = new EmptyAdminData();
private static final UserAccountQuery EMPTY_USER_ACCOUNTS = new EmptyUserAccountSet();
private static final DataAccountQuery EMPTY_DATA_ACCOUNTS = new EmptyDataAccountSet();
private static final ContractAccountQuery EMPTY_CONTRACT_ACCOUNTS = new EmptyContractAccountSet();

private static final ParticipantDataQuery EMPTY_PARTICIPANTS = new EmptyParticipantData();

@Override
public LedgerAdminDataQuery getAdminDataset() {
return EMPTY_ADMIN_DATA;
}

@Override
public UserAccountQuery getUserAccountSet() {
return EMPTY_USER_ACCOUNTS;
}

@Override
public DataAccountQuery getDataAccountSet() {
return EMPTY_DATA_ACCOUNTS;
}

@Override
public ContractAccountQuery getContractAccountset() {
return EMPTY_CONTRACT_ACCOUNTS;
}


private static class EmptyAdminData implements LedgerAdminDataQuery{

@Override
public LedgerAdminInfo getAdminInfo() {
return null;
}

@Override
public ParticipantDataQuery getParticipantDataset() {
return EMPTY_PARTICIPANTS;
}
}
private static class EmptyParticipantData implements ParticipantDataQuery{

@Override
public HashDigest getRootHash() {
return null;
}

@Override
public MerkleProof getProof(Bytes key) {
return null;
}

@Override
public long getParticipantCount() {
return 0;
}

@Override
public boolean contains(Bytes address) {
return false;
}

@Override
public ParticipantNode getParticipant(Bytes address) {
return null;
}

@Override
public ParticipantNode[] getParticipants() {
return null;
}
}
private static class EmptyUserAccountSet implements UserAccountQuery{

@Override
public AccountHeader[] getAccounts(int fromIndex, int count) {
return null;
}

@Override
public long getTotalCount() {
return 0;
}

@Override
public HashDigest getRootHash() {
return null;
}

@Override
public MerkleProof getProof(Bytes key) {
return null;
}

@Override
public UserAccount getUser(String address) {
return null;
}

@Override
public UserAccount getUser(Bytes address) {
return null;
}

@Override
public boolean contains(Bytes address) {
return false;
}

@Override
public UserAccount getUser(Bytes address, long version) {
return null;
}
}
private static class EmptyDataAccountSet implements DataAccountQuery{

@Override
public AccountHeader[] getAccounts(int fromIndex, int count) {
return null;
}

@Override
public HashDigest getRootHash() {
return null;
}

@Override
public long getTotalCount() {
return 0;
}

@Override
public MerkleProof getProof(Bytes address) {
return null;
}

@Override
public DataAccount getDataAccount(Bytes address) {
return null;
}

@Override
public DataAccount getDataAccount(Bytes address, long version) {
return null;
}
}

private static class EmptyContractAccountSet implements ContractAccountQuery{

@Override
public AccountHeader[] getAccounts(int fromIndex, int count) {
return null;
}

@Override
public HashDigest getRootHash() {
return null;
}

@Override
public long getTotalCount() {
return 0;
}

@Override
public MerkleProof getProof(Bytes address) {
return null;
}

@Override
public boolean contains(Bytes address) {
return false;
}

@Override
public ContractAccount getContract(Bytes address) {
return null;
}

@Override
public ContractAccount getContract(Bytes address, long version) {
return null;
}
}
}

+ 98
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/FullPermissionedSecurityManager.java View File

@@ -0,0 +1,98 @@
package com.jd.blockchain.ledger.core;

import java.util.Set;

import com.jd.blockchain.ledger.LedgerPermission;
import com.jd.blockchain.ledger.LedgerSecurityException;
import com.jd.blockchain.ledger.TransactionPermission;
import com.jd.blockchain.utils.Bytes;

class FullPermissionedSecurityManager implements LedgerSecurityManager {

public static final FullPermissionedSecurityManager INSTANCE = new FullPermissionedSecurityManager();

@Override
public SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) {
return new FullPermissionedPolicy(endpoints, nodes);
}

private static class FullPermissionedPolicy implements SecurityPolicy {

private Set<Bytes> endpoints;
private Set<Bytes> nodes;

public FullPermissionedPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) {
this.endpoints = endpoints;
this.nodes = nodes;
}

@Override
public Set<Bytes> getEndpoints() {
return endpoints;
}

@Override
public Set<Bytes> getNodes() {
return nodes;
}

@Override
public boolean isEndpointEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) {
return true;
}

@Override
public boolean isEndpointEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) {
return true;
}

@Override
public boolean isNodeEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) {
return true;
}

@Override
public boolean isNodeEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) {
return true;
}

@Override
public void checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy)
throws LedgerSecurityException {
}

@Override
public void checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy)
throws LedgerSecurityException {
}

@Override
public void checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException {
}

@Override
public void checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy)
throws LedgerSecurityException {
}

@Override
public boolean isEndpointValid(MultiIDsPolicy midPolicy) {
return true;
}

@Override
public boolean isNodeValid(MultiIDsPolicy midPolicy) {
return true;
}

@Override
public void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException {
}

@Override
public void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException {
}

}

}

+ 0
- 22
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/Gateway.java View File

@@ -1,22 +0,0 @@
package com.jd.blockchain.ledger.core;
import com.jd.blockchain.ledger.ParticipantNode;
/**
* @author hhq
* @version 1.0
* @created 14-6��-2018 12:13:32
*/
public class Gateway extends Node {
public ParticipantNode m_Participant;
public Gateway(){
}
public void finalize() throws Throwable {
super.finalize();
}
}

source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/GenesisLedgerStorageProxy.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenesisLedgerStorageProxy.java View File

@@ -1,3 +1,4 @@
package com.jd.blockchain.ledger.core;
//package com.jd.blockchain.ledger.core.impl;
//
//import com.jd.blockchain.storage.service.ExPolicyKVStorage;

+ 0
- 356
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminAccount.java View File

@@ -1,356 +0,0 @@
package com.jd.blockchain.ledger.core;
import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.LedgerSetting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.HashFunction;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.LedgerInitSetting;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
public class LedgerAdminAccount implements Transactional, LedgerAdministration {
static {
DataContractRegistry.register(LedgerMetadata.class);
}
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminAccount.class);
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR;
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR;
public static final String LEDGER_PRIVILEGE_PREFIX = "PVL" + LedgerConsts.KEY_SEPERATOR;
private final Bytes metaPrefix;
private final Bytes privilegePrefix;
private LedgerMetadata origMetadata;
private LedgerMetadataImpl metadata;
/**
* 原来的账本设置;
*
* <br>
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效;
*/
private LedgerSetting previousSetting;
/**
* 账本的参与节点;
*/
private ParticipantDataSet participants;
// /**
// * 账本的全局权限设置;
// */
// private PrivilegeDataSet privileges;
private ExPolicyKVStorage settingsStorage;
private HashDigest adminAccountHash;
private boolean readonly;
private boolean updated;
public HashDigest getHash() {
return adminAccountHash;
}
public boolean isReadonly() {
return readonly;
}
/**
* 初始化账本的管理账户;
*
* <br>
*
* 只在新建账本时调用此方法;
*
* @param ledgerSeed
* @param setting
* @param partiList
* @param exPolicyStorage
* @param versioningStorage
*/
public LedgerAdminAccount(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage,
VersioningKVStorage versioningStorage) {
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX);
this.privilegePrefix = Bytes.fromString(keyPrefix + LEDGER_PRIVILEGE_PREFIX);
ParticipantNode[] parties = initSetting.getConsensusParticipants();
if (parties.length == 0) {
throw new LedgerException("No participant!");
}
// 检查参与者列表是否已经按照 id 升序排列,并且 id 不冲突;
// 注:参与者的 id 要求从 0 开始编号,顺序依次递增,不允许跳空;
for (int i = 0; i < parties.length; i++) {
// if (parties[i].getAddress() != i) {
// throw new LedgerException("The id of participant isn't match the order of the
// participant list!");
// }
}
// 初始化元数据;
this.metadata = new LedgerMetadataImpl();
this.metadata.setSeed(initSetting.getLedgerSeed());
// 新配置;
this.metadata.setting = new LedgerConfiguration(initSetting.getConsensusProvider(),
initSetting.getConsensusSettings(), initSetting.getCryptoSetting());
this.previousSetting = new LedgerConfiguration(initSetting.getConsensusProvider(),
initSetting.getConsensusSettings(), initSetting.getCryptoSetting());
this.adminAccountHash = null;
// 基于原配置初始化参与者列表;
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX;
this.participants = new ParticipantDataSet(previousSetting.getCryptoSetting(), partiPrefix, exPolicyStorage,
versioningStorage);
for (ParticipantNode p : parties) {
this.participants.addConsensusParticipant(p);
}
// 初始化其它属性;
this.settingsStorage = exPolicyStorage;
this.readonly = false;
}
public LedgerAdminAccount(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage,
VersioningKVStorage versioningKVStorage, boolean readonly) {
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX);
this.privilegePrefix = Bytes.fromString(keyPrefix + LEDGER_PRIVILEGE_PREFIX);
this.settingsStorage = kvStorage;
this.readonly = readonly;
this.origMetadata = loadAndVerifySettings(adminAccountHash);
this.metadata = new LedgerMetadataImpl(origMetadata);
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储;
this.previousSetting = new LedgerConfiguration(metadata.getSetting());
this.adminAccountHash = adminAccountHash;
// this.privileges = new PrivilegeDataSet(metadata.getPrivilegesHash(),
// metadata.getSetting().getCryptoSetting(),
// PrefixAppender.prefix(LEDGER_PRIVILEGE_PREFIX, kvStorage),
// PrefixAppender.prefix(LEDGER_PRIVILEGE_PREFIX, versioningKVStorage),
// readonly);
// this.participants = new ParticipantDataSet(metadata.getParticipantsHash(),
// previousSetting.getCryptoSetting(),
// PrefixAppender.prefix(LEDGER_PARTICIPANT_PREFIX, kvStorage),
// PrefixAppender.prefix(LEDGER_PARTICIPANT_PREFIX, versioningKVStorage),
// readonly);
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX;
this.participants = new ParticipantDataSet(metadata.getParticipantsHash(), previousSetting.getCryptoSetting(),
partiPrefix, kvStorage, versioningKVStorage, readonly);
}
private LedgerMetadata loadAndVerifySettings(HashDigest adminAccountHash) {
// String base58Hash = adminAccountHash.toBase58();
// String key = encodeMetadataKey(base58Hash);
Bytes key = encodeMetadataKey(adminAccountHash);
byte[] bytes = settingsStorage.get(key);
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm());
if (!hashFunc.verify(adminAccountHash, bytes)) {
LOGGER.error("The hash verification of ledger settings fail! --[HASH=" + key + "]");
throw new LedgerException("The hash verification of ledger settings fail!");
}
return deserializeMetadata(bytes);
}
private Bytes encodeMetadataKey(HashDigest metadataHash) {
// return LEDGER_META_PREFIX + metadataHash;
// return metaPrefix + metadataHash;
return metaPrefix.concat(metadataHash);
}
/*
* (non-Javadoc)
*
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata()
*/
@Override
public LedgerMetadata getMetadata() {
return metadata;
}
/**
* 返回原来的账本配置;
*
* <br>
* 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSetting)} 做出了新的更改;
*
* @return
*/
public LedgerSetting getPreviousSetting() {
return previousSetting;
}
/**
* 返回当前设置的账本配置;
*
* @return
*/
public LedgerSetting getSetting() {
return metadata.getSetting();
}
/**
* 更新账本配置;
*
* @param ledgerSetting
*/
public void setLedgerSetting(LedgerSetting ledgerSetting) {
if (readonly) {
throw new IllegalArgumentException("This merkle dataset is readonly!");
}
metadata.setSetting(ledgerSetting);
}
@Override
public long getParticipantCount() {
return participants.getParticipantCount();
}
// /*
// * (non-Javadoc)
// *
// * @see
// *
// com.jd.blockchain.ledger.core.LedgerAdministration#getParticipant(java.lang.
// * String)
// */
// @Override
// public ParticipantNode getParticipant(int id) {
// return participants.getParticipant(id);
// }
@Override
public ParticipantNode[] getParticipants() {
return participants.getParticipants();
}
/**
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常;
*
* @param participant
*/
public void addParticipant(ParticipantNode participant) {
participants.addConsensusParticipant(participant);
}
@Override
public boolean isUpdated() {
return updated || participants.isUpdated();
}
@Override
public void commit() {
if (!isUpdated()) {
return;
}
participants.commit();
metadata.setParticipantsHash(participants.getRootHash());
// 基于之前的密码配置来计算元数据的哈希;
byte[] metadataBytes = serializeMetadata(metadata);
HashFunction hashFunc = Crypto
.getHashFunction(previousSetting.getCryptoSetting().getHashAlgorithm());
HashDigest metadataHash = hashFunc.hash(metadataBytes);
if (adminAccountHash == null || !adminAccountHash.equals(metadataHash)) {
// update modify;
// String base58MetadataHash = metadataHash.toBase58();
// String metadataKey = encodeMetadataKey(base58MetadataHash);
Bytes metadataKey = encodeMetadataKey(metadataHash);
boolean nx = settingsStorage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING);
if (!nx) {
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据;
// throw new LedgerException(
// "Ledger metadata already exist! --[LedgerMetadataHash=" + base58MetadataHash
// + "]");
// LOGGER.warn("Ledger metadata already exist! --[MetadataHash=" +
// base58MetadataHash + "]");
}
adminAccountHash = metadataHash;
}
updated = false;
}
private LedgerMetadata deserializeMetadata(byte[] bytes) {
return BinaryProtocol.decode(bytes);
}
private byte[] serializeMetadata(LedgerMetadataImpl config) {
return BinaryProtocol.encode(config, LedgerMetadata.class);
}
@Override
public void cancel() {
if (!isUpdated()) {
return;
}
participants.cancel();
metadata = new LedgerMetadataImpl(origMetadata);
}
public static class LedgerMetadataImpl implements LedgerMetadata {
private byte[] seed;
private LedgerSetting setting;
private HashDigest participantsHash;
public LedgerMetadataImpl() {
}
public LedgerMetadataImpl(LedgerMetadata metadata) {
this.seed = metadata.getSeed();
this.setting = metadata.getSetting();
this.participantsHash = metadata.getParticipantsHash();
}
@Override
public byte[] getSeed() {
return seed;
}
@Override
public LedgerSetting getSetting() {
return setting;
}
@Override
public HashDigest getParticipantsHash() {
return participantsHash;
}
public void setSeed(byte[] seed) {
this.seed = seed;
}
public void setSetting(LedgerSetting setting) {
// copy a new instance;
this.setting = new LedgerConfiguration(setting);
}
public void setParticipantsHash(HashDigest participantsHash) {
this.participantsHash = participantsHash;
}
}
}

+ 12
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataQuery.java View File

@@ -0,0 +1,12 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.LedgerAdminInfo;
import com.jd.blockchain.ledger.ParticipantDataQuery;

public interface LedgerAdminDataQuery {
LedgerAdminInfo getAdminInfo();

ParticipantDataQuery getParticipantDataset();

}

+ 481
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java View File

@@ -0,0 +1,481 @@
package com.jd.blockchain.ledger.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.HashFunction;
import com.jd.blockchain.ledger.LedgerAdminInfo;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.LedgerInitSetting;
import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.LedgerMetadata_V2;
import com.jd.blockchain.ledger.LedgerSettings;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.ledger.RolePrivilegeSettings;
import com.jd.blockchain.ledger.UserRolesSettings;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
public class LedgerAdminDataset implements Transactional, LedgerAdminDataQuery, LedgerAdminInfo {
static {
DataContractRegistry.register(LedgerMetadata.class);
DataContractRegistry.register(LedgerMetadata_V2.class);
}
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminDataset.class);
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR;
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR;
public static final String LEDGER_SETTING_PREFIX = "SET" + LedgerConsts.KEY_SEPERATOR;
public static final String ROLE_PRIVILEGE_PREFIX = "RPV" + LedgerConsts.KEY_SEPERATOR;
public static final String USER_ROLE_PREFIX = "URO" + LedgerConsts.KEY_SEPERATOR;
private final Bytes metaPrefix;
private final Bytes settingPrefix;
private LedgerMetadata_V2 origMetadata;
private LedgerMetadataInfo metadata;
/**
* 原来的账本设置;
*
* <br>
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效;
*/
private LedgerSettings previousSettings;
private HashDigest previousSettingHash;
/**
* 账本的参与节点;
*/
private ParticipantDataset participants;
/**
* “角色-权限”数据集;
*/
private RolePrivilegeDataset rolePrivileges;
/**
* “用户-角色”数据集;
*/
private UserRoleDataset userRoles;
/**
* 账本参数配置;
*/
private LedgerSettings settings;
private ExPolicyKVStorage storage;
private HashDigest adminDataHash;
private boolean readonly;
private boolean updated;
public HashDigest getHash() {
return adminDataHash;
}
public boolean isReadonly() {
return readonly;
}
void setReadonly() {
this.readonly = true;
}
public LedgerSettings getPreviousSetting() {
return previousSettings;
}
@Override
public RolePrivilegeSettings getRolePrivileges() {
return rolePrivileges;
}
@Override
public UserRolesSettings getUserRoles() {
return userRoles;
}
@Override
public LedgerAdminInfo getAdminInfo() {
return this;
}
/**
* 初始化账本的管理账户;
*
* <br>
*
* 只在新建账本时调用此方法;
*
* @param ledgerSeed
* @param settings
* @param partiList
* @param exPolicyStorage
* @param versioningStorage
*/
public LedgerAdminDataset(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage,
VersioningKVStorage versioningStorage) {
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX);
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX);
ParticipantNode[] parties = initSetting.getConsensusParticipants();
if (parties.length == 0) {
throw new LedgerException("No participant!");
}
// 初始化元数据;
this.metadata = new LedgerMetadataInfo();
this.metadata.setSeed(initSetting.getLedgerSeed());
// 新配置;
this.settings = new LedgerConfiguration(initSetting.getConsensusProvider(), initSetting.getConsensusSettings(),
initSetting.getCryptoSetting());
this.previousSettings = new LedgerConfiguration(settings);
this.previousSettingHash = null;
this.adminDataHash = null;
// 基于原配置初始化参与者列表;
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX;
this.participants = new ParticipantDataset(previousSettings.getCryptoSetting(), partiPrefix, exPolicyStorage,
versioningStorage);
for (ParticipantNode p : parties) {
this.participants.addConsensusParticipant(p);
}
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX;
this.rolePrivileges = new RolePrivilegeDataset(this.settings.getCryptoSetting(), rolePrivilegePrefix,
exPolicyStorage, versioningStorage);
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX;
this.userRoles = new UserRoleDataset(this.settings.getCryptoSetting(), userRolePrefix, exPolicyStorage,
versioningStorage);
// 初始化其它属性;
this.storage = exPolicyStorage;
this.readonly = false;
}
public LedgerAdminDataset(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage,
VersioningKVStorage versioningKVStorage, boolean readonly) {
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX);
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX);
this.storage = kvStorage;
this.readonly = readonly;
this.origMetadata = loadAndVerifyMetadata(adminAccountHash);
this.metadata = new LedgerMetadataInfo(origMetadata);
this.settings = loadAndVerifySettings(metadata.getSettingsHash());
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储;
this.previousSettings = new LedgerConfiguration(settings);
this.previousSettingHash = metadata.getSettingsHash();
this.adminDataHash = adminAccountHash;
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX;
this.participants = new ParticipantDataset(metadata.getParticipantsHash(), previousSettings.getCryptoSetting(),
partiPrefix, kvStorage, versioningKVStorage, readonly);
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX;
this.rolePrivileges = new RolePrivilegeDataset(metadata.getRolePrivilegesHash(),
previousSettings.getCryptoSetting(), rolePrivilegePrefix, kvStorage, versioningKVStorage, readonly);
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX;
this.userRoles = new UserRoleDataset(metadata.getUserRolesHash(), previousSettings.getCryptoSetting(),
userRolePrefix, kvStorage, versioningKVStorage, readonly);
}
private LedgerSettings loadAndVerifySettings(HashDigest settingsHash) {
if (settingsHash == null) {
return null;
}
Bytes key = encodeSettingsKey(settingsHash);
byte[] bytes = storage.get(key);
HashFunction hashFunc = Crypto.getHashFunction(settingsHash.getAlgorithm());
if (!hashFunc.verify(settingsHash, bytes)) {
String errorMsg = "Verification of the hash for ledger setting failed! --[HASH=" + key + "]";
LOGGER.error(errorMsg);
throw new LedgerException(errorMsg);
}
return deserializeSettings(bytes);
}
private LedgerSettings deserializeSettings(byte[] bytes) {
return BinaryProtocol.decode(bytes);
}
private byte[] serializeSetting(LedgerSettings setting) {
return BinaryProtocol.encode(setting, LedgerSettings.class);
}
private LedgerMetadata_V2 loadAndVerifyMetadata(HashDigest adminAccountHash) {
Bytes key = encodeMetadataKey(adminAccountHash);
byte[] bytes = storage.get(key);
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm());
if (!hashFunc.verify(adminAccountHash, bytes)) {
String errorMsg = "Verification of the hash for ledger metadata failed! --[HASH=" + key + "]";
LOGGER.error(errorMsg);
throw new LedgerException(errorMsg);
}
return deserializeMetadata(bytes);
}
private Bytes encodeSettingsKey(HashDigest settingsHash) {
return settingPrefix.concat(settingsHash);
}
private Bytes encodeMetadataKey(HashDigest metadataHash) {
// return LEDGER_META_PREFIX + metadataHash;
// return metaPrefix + metadataHash;
return metaPrefix.concat(metadataHash);
}
/*
* (non-Javadoc)
*
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata()
*/
@Override
public LedgerMetadata_V2 getMetadata() {
return metadata;
}
// /**
// * 返回原来的账本配置;
// *
// * <br>
// * 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSettings)} 做出了新的更改;
// *
// * @return
// */
// public LedgerSettings getPreviousSetting() {
// return previousSettings;
// }
/**
* 返回当前设置的账本配置;
*
* @return
*/
@Override
public LedgerSettings getSettings() {
return settings;
}
/**
* 更新账本配置;
*
* @param ledgerSetting
*/
public void setLedgerSetting(LedgerSettings ledgerSetting) {
if (readonly) {
throw new IllegalArgumentException("This merkle dataset is readonly!");
}
settings = ledgerSetting;
updated = true;
}
@Override
public long getParticipantCount() {
return participants.getParticipantCount();
}
@Override
public ParticipantNode[] getParticipants() {
return participants.getParticipants();
}
@Override
public ParticipantDataset getParticipantDataset() {
return participants;
}
/**
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常;
*
* @param participant
*/
public void addParticipant(ParticipantNode participant) {
participants.addConsensusParticipant(participant);
}
/**
* 更新参与方的状态参数;
*
* @param participant
*/
public void updateParticipant(ParticipantNode participant) {
participants.updateConsensusParticipant(participant);
}
@Override
public boolean isUpdated() {
return updated || participants.isUpdated() || rolePrivileges.isUpdated() || userRoles.isUpdated();
}
@Override
public void commit() {
if (!isUpdated()) {
return;
}
// 计算并更新参与方集合的根哈希;
participants.commit();
metadata.setParticipantsHash(participants.getRootHash());
// 计算并更新角色权限集合的根哈希;
rolePrivileges.commit();
metadata.setRolePrivilegesHash(rolePrivileges.getRootHash());
// 计算并更新用户角色授权集合的根哈希;
userRoles.commit();
metadata.setUserRolesHash(userRoles.getRootHash());
// 当前区块上下文的密码参数设置的哈希函数;
HashFunction hashFunc = Crypto.getHashFunction(previousSettings.getCryptoSetting().getHashAlgorithm());
// 计算并更新参数配置的哈希;
if (settings == null) {
throw new LedgerException("Missing ledger settings!");
}
byte[] settingsBytes = serializeSetting(settings);
HashDigest settingsHash = hashFunc.hash(settingsBytes);
metadata.setSettingsHash(settingsHash);
if (previousSettingHash == null || !previousSettingHash.equals(settingsHash)) {
Bytes settingsKey = encodeSettingsKey(settingsHash);
boolean nx = storage.set(settingsKey, settingsBytes, ExPolicy.NOT_EXISTING);
if (!nx) {
String base58MetadataHash = settingsHash.toBase58();
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据;
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]";
LOGGER.warn(errMsg);
throw new LedgerException(errMsg);
}
}
// 基于之前的密码配置来计算元数据的哈希;
byte[] metadataBytes = serializeMetadata(metadata);
HashDigest metadataHash = hashFunc.hash(metadataBytes);
if (adminDataHash == null || !adminDataHash.equals(metadataHash)) {
// update modify;
// String base58MetadataHash = metadataHash.toBase58();
// String metadataKey = encodeMetadataKey(base58MetadataHash);
Bytes metadataKey = encodeMetadataKey(metadataHash);
boolean nx = storage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING);
if (!nx) {
String base58MetadataHash = metadataHash.toBase58();
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据;
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]";
LOGGER.warn(errMsg);
throw new LedgerException(errMsg);
}
adminDataHash = metadataHash;
}
updated = false;
}
private LedgerMetadata_V2 deserializeMetadata(byte[] bytes) {
return BinaryProtocol.decode(bytes);
}
private byte[] serializeMetadata(LedgerMetadataInfo config) {
return BinaryProtocol.encode(config, LedgerMetadata_V2.class);
}
@Override
public void cancel() {
if (!isUpdated()) {
return;
}
participants.cancel();
metadata =origMetadata == null ? new LedgerMetadataInfo() : new LedgerMetadataInfo(origMetadata);
}
public static class LedgerMetadataInfo implements LedgerMetadata_V2 {
private byte[] seed;
// private LedgerSetting setting;
private HashDigest participantsHash;
private HashDigest settingsHash;
private HashDigest rolePrivilegesHash;
private HashDigest userRolesHash;
public LedgerMetadataInfo() {
}
public LedgerMetadataInfo(LedgerMetadata_V2 metadata) {
this.seed = metadata.getSeed();
this.participantsHash = metadata.getParticipantsHash();
this.settingsHash = metadata.getSettingsHash();
this.rolePrivilegesHash = metadata.getRolePrivilegesHash();
this.userRolesHash = metadata.getUserRolesHash();
}
@Override
public byte[] getSeed() {
return seed;
}
@Override
public HashDigest getSettingsHash() {
return settingsHash;
}
@Override
public HashDigest getParticipantsHash() {
return participantsHash;
}
@Override
public HashDigest getRolePrivilegesHash() {
return rolePrivilegesHash;
}
@Override
public HashDigest getUserRolesHash() {
return userRolesHash;
}
public void setSeed(byte[] seed) {
this.seed = seed;
}
public void setSettingsHash(HashDigest settingHash) {
this.settingsHash = settingHash;
}
public void setParticipantsHash(HashDigest participantsHash) {
this.participantsHash = participantsHash;
}
public void setRolePrivilegesHash(HashDigest rolePrivilegesHash) {
this.rolePrivilegesHash = rolePrivilegesHash;
}
public void setUserRolesHash(HashDigest userRolesHash) {
this.userRolesHash = userRolesHash;
}
}
}

+ 0
- 5
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminPrivilege.java View File

@@ -1,5 +0,0 @@
package com.jd.blockchain.ledger.core;

public enum LedgerAdminPrivilege {

}

+ 0
- 16
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdministration.java View File

@@ -1,16 +0,0 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.ParticipantNode;

public interface LedgerAdministration {

LedgerMetadata getMetadata();
long getParticipantCount();

// ParticipantNode getParticipant(int id);
ParticipantNode[] getParticipants();
}

source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerBlockData.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerBlockData.java View File

@@ -1,4 +1,4 @@
package com.jd.blockchain.ledger.core.impl;
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;

+ 3
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerConfiguration.java View File

@@ -1,10 +1,10 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.LedgerSetting;
import com.jd.blockchain.ledger.LedgerSettings;
import com.jd.blockchain.utils.Bytes;

public class LedgerConfiguration implements LedgerSetting {
public class LedgerConfiguration implements LedgerSettings {

private String consensusProvider;

@@ -16,7 +16,7 @@ public class LedgerConfiguration implements LedgerSetting {
this.cryptoSetting = new CryptoConfig();
}

public LedgerConfiguration(LedgerSetting origSetting) {
public LedgerConfiguration(LedgerSettings origSetting) {
if (origSetting != null) {
this.consensusProvider = origSetting.getConsensusProvider();
this.consensusSetting = origSetting.getConsensusSetting();


+ 19
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataQuery.java View File

@@ -0,0 +1,19 @@
package com.jd.blockchain.ledger.core;

/**
* {@link LedgerDataset} 表示账本在某一个区块上的数据集合;
*
* @author huanghaiquan
*
*/
public interface LedgerDataQuery{
LedgerAdminDataQuery getAdminDataset();

UserAccountQuery getUserAccountSet();

DataAccountQuery getDataAccountSet();

ContractAccountQuery getContractAccountset();

}

+ 0
- 21
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataSet.java View File

@@ -1,21 +0,0 @@
package com.jd.blockchain.ledger.core;

/**
* {@link LedgerDataSet} 表示账本在某一个区块上的数据集合;
*
* @author huanghaiquan
*
*/
public interface LedgerDataSet{
boolean isReadonly();

LedgerAdminAccount getAdminAccount();

UserAccountSet getUserAccountSet();

DataAccountSet getDataAccountSet();

ContractAccountSet getContractAccountSet();

}

source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerDataSetImpl.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerDataset.java View File

@@ -1,33 +1,31 @@
package com.jd.blockchain.ledger.core.impl;
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.core.*;
import com.jd.blockchain.utils.Transactional;

public class LedgerDataSetImpl implements LedgerDataSet, Transactional {
public class LedgerDataset implements LedgerDataQuery, Transactional {

private LedgerAdminAccount adminAccount;
private LedgerAdminDataset adminDataset;

private UserAccountSet userAccountSet;

private DataAccountSet dataAccountSet;

private ContractAccountSet contractAccountSet;
private boolean readonly;

private boolean readonly;

/**
* Create new block;
*
* @param adminAccount
* @param userAccountSet
* @param dataAccountSet
* @param contractAccountSet
* @param readonly
*/
public LedgerDataSetImpl(LedgerAdminAccount adminAccount,
UserAccountSet userAccountSet, DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet,
boolean readonly) {
this.adminAccount = adminAccount;
public LedgerDataset(LedgerAdminDataset adminAccount, UserAccountSet userAccountSet,
DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet, boolean readonly) {
this.adminDataset = adminAccount;
this.userAccountSet = userAccountSet;
this.dataAccountSet = dataAccountSet;
this.contractAccountSet = contractAccountSet;
@@ -36,8 +34,8 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional {
}

@Override
public LedgerAdminAccount getAdminAccount() {
return adminAccount;
public LedgerAdminDataset getAdminDataset() {
return adminDataset;
}

@Override
@@ -51,13 +49,13 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional {
}

@Override
public ContractAccountSet getContractAccountSet() {
public ContractAccountSet getContractAccountset() {
return contractAccountSet;
}

@Override
public boolean isUpdated() {
return adminAccount.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated()
return adminDataset.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated()
|| contractAccountSet.isUpdated();
}

@@ -70,7 +68,7 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional {
return;
}

adminAccount.commit();
adminDataset.commit();
userAccountSet.commit();
dataAccountSet.commit();
contractAccountSet.commit();
@@ -78,15 +76,22 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional {

@Override
public void cancel() {
adminAccount.cancel();
adminDataset.cancel();
userAccountSet.cancel();
dataAccountSet.cancel();
contractAccountSet.cancel();
}

@Override
public boolean isReadonly() {
return readonly;
}

void setReadonly() {
this.readonly = true;
this.adminDataset.setReadonly();
this.userAccountSet.setReadonly();
this.dataAccountSet.setReadonly();
this.contractAccountSet.setReadonly();
}

}

+ 18
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java View File

@@ -11,7 +11,7 @@ import com.jd.blockchain.ledger.TransactionRequest;
* <p>
*
* {@link LedgerEditor} 以上一个区块作为数据编辑的起点; <br>
* 对账本数据({@link #getDataSet()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点;
* 对账本数据({@link #getDataset()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点;
* <br>
*
* @author huanghaiquan
@@ -33,11 +33,25 @@ public interface LedgerEditor {
*/
long getBlockHeight();

/**
* 最新的账本数据集;
*
* @return
*/
LedgerDataset getLedgerDataset();

/**
* 最新的交易集合;
*
* @return
*/
TransactionSet getTransactionSet();

/**
* 开始新事务;<br>
*
* 方法返回之前,将会校验交易请求的用户签名列表和节点签名列表,并在后续对数据集
* {@link LedgerTransactionContext#getDataSet()} 的操作时,校验这些用户和节点是否具备权限;<br>
* {@link LedgerTransactionContext#getDataset()} 的操作时,校验这些用户和节点是否具备权限;<br>
*
* 校验失败将引发异常 {@link LedgerException};
* <p>
@@ -52,7 +66,8 @@ public interface LedgerEditor {
*
*
*
* 注:方法不解析、不执行交易中的操作;<p>
* 注:方法不解析、不执行交易中的操作;
* <p>
*
* @param txRequest 交易请求;
* @return


source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerInitPermission.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerInitProposal.java View File

@@ -13,8 +13,8 @@ import com.jd.blockchain.ledger.LedgerInitOperation;
* @author huanghaiquan
*
*/
@DataContract(code = DataCodes.METADATA_INIT_PERMISSION)
public interface LedgerInitPermission {
@DataContract(code = DataCodes.METADATA_INIT_PROPOSAL)
public interface LedgerInitProposal {

/**
* 做出许可的参与方 ID;

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save