# Conflicts: # source/contract/contract-samples/pom.xml # source/pom.xmltags/1.1.0
@@ -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 |
@@ -3,8 +3,6 @@ | |||||
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) | [![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) | |||||
------------------------------------------------------------------------ | ------------------------------------------------------------------------ | ||||
@@ -11,9 +11,8 @@ | |||||
<dependencies> | <dependencies> | ||||
<dependency> | <dependency> | ||||
<groupId>org.slf4j</groupId> | |||||
<artifactId>slf4j-api</artifactId> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-log4j2</artifactId> | |||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
</project> | </project> |
@@ -7,12 +7,14 @@ package com.jd.blockchain.consts; | |||||
* | * | ||||
*/ | */ | ||||
public interface DataCodes { | public interface DataCodes { | ||||
public static final int BYTES_VALUE = 0x80; | |||||
public static final int BYTES_VALUE_LIST = 0x81; | |||||
public static final int MERKLE_SNAPSHOT = 0x070; | |||||
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; | public static final int BLOCK = 0x100; | ||||
@@ -22,6 +24,8 @@ public interface DataCodes { | |||||
public static final int DATA_SNAPSHOT = 0x130; | public static final int DATA_SNAPSHOT = 0x130; | ||||
public static final int LEDGER_ADMIN_INFO = 0x131; | |||||
public static final int TX = 0x200; | public static final int TX = 0x200; | ||||
public static final int TX_LEDGER = 0x201; | public static final int TX_LEDGER = 0x201; | ||||
@@ -49,15 +53,43 @@ public interface DataCodes { | |||||
public static final int TX_OP_CONTRACT_EVENT_SEND = 0x340; | 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 = 0x600; | ||||
public static final int METADATA_V2 = 0x601; | |||||
public static final int METADATA_INIT_SETTING = 0x610; | 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; | public static final int METADATA_INIT_DECISION = 0x612; | ||||
@@ -65,17 +97,27 @@ public interface DataCodes { | |||||
public static final int METADATA_CONSENSUS_PARTICIPANT = 0x621; | 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_NODE = 0x630; | ||||
public static final int METADATA_CONSENSUS_SETTING = 0x631; | 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; | public static final int METADATA_CRYPTO_SETTING = 0x642; | ||||
public static final int METADATA_CRYPTO_SETTING_PROVIDER = 0x643; | public static final int METADATA_CRYPTO_SETTING_PROVIDER = 0x643; | ||||
// public static final int ACCOUNT = 0x700; | |||||
// public static final int ACCOUNT = 0x700; | |||||
public static final int ACCOUNT_HEADER = 0x710; | public static final int ACCOUNT_HEADER = 0x710; | ||||
@@ -83,11 +125,10 @@ public interface DataCodes { | |||||
public static final int DATA = 0x900; | public static final int DATA = 0x900; | ||||
//contract related; | |||||
// contract related; | |||||
public static final int CONTRACT = 0xA00; | public static final int CONTRACT = 0xA00; | ||||
//...0xA19 | |||||
// ...0xA19 | |||||
public static final int HASH = 0xB00; | public static final int HASH = 0xB00; | ||||
public static final int HASH_OBJECT = 0xB10; | public static final int HASH_OBJECT = 0xB10; | ||||
@@ -100,6 +141,8 @@ public interface DataCodes { | |||||
public static final int ENUM_TYPE_BYTES_VALUE_TYPE = 0xB23; | 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 = 0xB30; | ||||
public static final int DIGITALSIGNATURE_BODY = 0xB31; | public static final int DIGITALSIGNATURE_BODY = 0xB31; | ||||
@@ -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)); | |||||
} | |||||
} |
@@ -1,74 +0,0 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> | |||||
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 --> | |||||
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 --> | |||||
<configuration status="WARN" monitorInterval="60"> | |||||
<!--先定义所有的appender --> | |||||
<appenders> | |||||
<!--这个输出控制台的配置 --> | |||||
<console name="Console" target="SYSTEM_OUT"> | |||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> | |||||
<ThresholdFilter level="error" onMatch="ACCEPT" | |||||
onMismatch="DENY" /> | |||||
<!--输出日志的格式 --> | |||||
<PatternLayout | |||||
pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" /> | |||||
</console> | |||||
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用 --> | |||||
<File name="log" fileName="../logs/test.log" append="false"> | |||||
<PatternLayout | |||||
pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" /> | |||||
</File> | |||||
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 --> | |||||
<RollingFile name="PeerRollingInfo" | |||||
fileName="../logs/peer.out.info.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/peer.out.info-%d{yyyy-MM-dd}-%i.log"> | |||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> | |||||
<ThresholdFilter level="info" onMatch="ACCEPT" | |||||
onMismatch="DENY" /> | |||||
<PatternLayout | |||||
pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> | |||||
<Policies> | |||||
<TimeBasedTriggeringPolicy /> | |||||
<SizeBasedTriggeringPolicy size="100 MB" /> | |||||
</Policies> | |||||
</RollingFile> | |||||
<RollingFile name="PeerRollingWarn" | |||||
fileName="../logs/peer.out.warn.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/peer.out.warn-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="warn" onMatch="ACCEPT" | |||||
onMismatch="DENY" /> | |||||
<PatternLayout | |||||
pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> | |||||
<Policies> | |||||
<TimeBasedTriggeringPolicy /> | |||||
<SizeBasedTriggeringPolicy size="100 MB" /> | |||||
</Policies> | |||||
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --> | |||||
<DefaultRolloverStrategy max="20" /> | |||||
</RollingFile> | |||||
<RollingFile name="PeerRollingError" | |||||
fileName="../logs/peer.out.error.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/peer.out.error-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="error" onMatch="ACCEPT" | |||||
onMismatch="DENY" /> | |||||
<PatternLayout | |||||
pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> | |||||
<Policies> | |||||
<TimeBasedTriggeringPolicy /> | |||||
<SizeBasedTriggeringPolicy size="100 MB" /> | |||||
</Policies> | |||||
</RollingFile> | |||||
</appenders> | |||||
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 --> | |||||
<loggers> | |||||
<!--过滤掉spring的一些DEBUG信息 --> | |||||
<logger name="org.springframework" level="INFO"></logger> | |||||
<root level="all"> | |||||
<appender-ref ref="Console" /> | |||||
<appender-ref ref="PeerRollingInfo" /> | |||||
<appender-ref ref="PeerRollingWarn" /> | |||||
<appender-ref ref="PeerRollingError" /> | |||||
</root> | |||||
</loggers> | |||||
</configuration> |
@@ -15,9 +15,16 @@ | |||||
<artifactId>utils-common</artifactId> | <artifactId>utils-common</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-log4j2</artifactId> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>junit</groupId> | <groupId>junit</groupId> | ||||
<artifactId>junit</artifactId> | <artifactId>junit</artifactId> | ||||
<scope>test</scope> | |||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
</project> | </project> |
@@ -42,6 +42,10 @@ public class BinaryProtocol { | |||||
long version = HeaderEncoder.resolveVersion(bytes); | long version = HeaderEncoder.resolveVersion(bytes); | ||||
DataContractEncoder encoder = DataContractContext.ENCODER_LOOKUP.lookup(code, version); | DataContractEncoder encoder = DataContractContext.ENCODER_LOOKUP.lookup(code, version); | ||||
if (encoder == null) { | |||||
throw new DataContractException( | |||||
String.format("No data contract was registered with code[%s] and version[%s]!", code, version)); | |||||
} | |||||
return encoder.decode(bytes.getInputStream()); | return encoder.decode(bytes.getInputStream()); | ||||
} | } | ||||
@@ -2,11 +2,18 @@ package com.jd.blockchain.consensus.bftsmart; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import java.util.Properties; | 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.ledger.ParticipantNode; | ||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | import com.jd.blockchain.tools.keygen.KeyGenCommand; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.PropertiesUtils; | import com.jd.blockchain.utils.PropertiesUtils; | ||||
import com.jd.blockchain.utils.Property; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | import com.jd.blockchain.utils.codec.Base58Utils; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import com.jd.blockchain.utils.net.NetworkAddress; | 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 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; | private static Properties CONFIG_TEMPLATE; | ||||
@@ -164,6 +173,30 @@ public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||||
return config; | 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) { | private static String keyOfNode(String pattern, int id) { | ||||
return String.format(pattern, id); | return String.format(pattern, id); | ||||
} | } | ||||
@@ -224,4 +257,52 @@ public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||||
PropertiesUtils.setValues(props, bftsmartSettings.getSystemConfigs()); | 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; | |||||
} | |||||
} | } |
@@ -51,11 +51,13 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer | |||||
private BftsmartConsensusManageService manageService; | private BftsmartConsensusManageService manageService; | ||||
private volatile BftsmartTopology topology; | private volatile BftsmartTopology topology; | ||||
private volatile BftsmartConsensusSettings setting; | private volatile BftsmartConsensusSettings setting; | ||||
private TOMConfiguration tomConfig; | private TOMConfiguration tomConfig; | ||||
private TOMConfiguration outerTomConfig; | private TOMConfiguration outerTomConfig; | ||||
private HostsConfig hostsConfig; | private HostsConfig hostsConfig; | ||||
@@ -1,6 +1,8 @@ | |||||
package com.jd.blockchain.consensus; | package com.jd.blockchain.consensus; | ||||
import com.jd.blockchain.ledger.ParticipantInfo; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
import java.util.Properties; | import java.util.Properties; | ||||
@@ -16,6 +18,8 @@ public interface ConsensusSettingsBuilder { | |||||
* @return | * @return | ||||
*/ | */ | ||||
ConsensusSettings createSettings(Properties props, ParticipantNode[] participantNodes); | ConsensusSettings createSettings(Properties props, ParticipantNode[] participantNodes); | ||||
Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo); | |||||
Properties createPropertiesTemplate(); | Properties createPropertiesTemplate(); | ||||
@@ -8,6 +8,7 @@ | |||||
*/ | */ | ||||
package com.jd.blockchain.consensus.mq; | package com.jd.blockchain.consensus.mq; | ||||
import com.jd.blockchain.consensus.ConsensusProviders; | |||||
import com.jd.blockchain.consensus.ConsensusSettings; | import com.jd.blockchain.consensus.ConsensusSettings; | ||||
import com.jd.blockchain.consensus.ConsensusSettingsBuilder; | import com.jd.blockchain.consensus.ConsensusSettingsBuilder; | ||||
import com.jd.blockchain.consensus.NodeSettings; | 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.MsgQueueNetworkSettings; | ||||
import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | ||||
import com.jd.blockchain.crypto.AddressEncoding; | import com.jd.blockchain.crypto.AddressEncoding; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.ParticipantInfo; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.PropertiesUtils; | import com.jd.blockchain.utils.PropertiesUtils; | ||||
import com.jd.blockchain.utils.codec.Base58Utils; | 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.BytesUtils; | ||||
import com.jd.blockchain.utils.io.FileUtils; | import com.jd.blockchain.utils.io.FileUtils; | ||||
import com.jd.blockchain.utils.net.NetworkAddress; | 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_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; | private static Properties CONFIG_TEMPLATE; | ||||
static { | static { | ||||
@@ -129,7 +134,7 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||||
String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | ||||
String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | ||||
PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey); | |||||
PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey); | |||||
// PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | // PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | ||||
resolvingProps.remove(keyOfPubkey); | resolvingProps.remove(keyOfPubkey); | ||||
@@ -145,6 +150,48 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||||
return consensusConfig; | 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 | @Override | ||||
public Properties createPropertiesTemplate() { | public Properties createPropertiesTemplate() { | ||||
return PropertiesUtils.cloneFrom(CONFIG_TEMPLATE); | return PropertiesUtils.cloneFrom(CONFIG_TEMPLATE); | ||||
@@ -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; | |||||
} | |||||
} |
@@ -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> | |||||
``` |
@@ -10,10 +10,6 @@ | |||||
<artifactId>contract-maven-plugin</artifactId> | <artifactId>contract-maven-plugin</artifactId> | ||||
<packaging>maven-plugin</packaging> | <packaging>maven-plugin</packaging> | ||||
<properties> | |||||
<maven.version>3.3.9</maven.version> | |||||
</properties> | |||||
<dependencies> | <dependencies> | ||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
@@ -39,59 +35,29 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.github.javaparser</groupId> | |||||
<artifactId>javaparser-core</artifactId> | |||||
<version>${javaparser.version}</version> | |||||
</dependency> | |||||
<!-- new --> | |||||
<dependency> | <dependency> | ||||
<groupId>org.apache.maven</groupId> | <groupId>org.apache.maven</groupId> | ||||
<artifactId>maven-plugin-api</artifactId> | <artifactId>maven-plugin-api</artifactId> | ||||
<version>3.3.9</version> | <version>3.3.9</version> | ||||
</dependency> | </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> | <dependency> | ||||
<groupId>org.apache.maven.plugin-tools</groupId> | <groupId>org.apache.maven.plugin-tools</groupId> | ||||
<artifactId>maven-plugin-annotations</artifactId> | <artifactId>maven-plugin-annotations</artifactId> | ||||
<version>3.6.0</version> | <version>3.6.0</version> | ||||
<scope>provided</scope> | |||||
</dependency> | </dependency> | ||||
<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> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
@@ -103,27 +69,6 @@ | |||||
<artifactId>maven-plugin-plugin</artifactId> | <artifactId>maven-plugin-plugin</artifactId> | ||||
<version>3.5</version> | <version>3.5</version> | ||||
</plugin> | </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> | </project> |
@@ -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); | |||||
} | |||||
} | |||||
} |
@@ -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,29 +7,12 @@ import java.io.InputStream; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | import com.jd.blockchain.crypto.PrivKey; | ||||
import com.jd.blockchain.crypto.PubKey; | 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.BlockchainService; | ||||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | 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.Bytes; | ||||
import com.jd.blockchain.utils.codec.Base58Utils; | import com.jd.blockchain.utils.codec.Base58Utils; | ||||
import com.jd.blockchain.utils.net.NetworkAddress; | import com.jd.blockchain.utils.net.NetworkAddress; | ||||
@@ -47,8 +30,8 @@ public enum ContractDeployExeUtil { | |||||
PubKey pub = null; | PubKey pub = null; | ||||
PrivKey prv = null; | PrivKey prv = null; | ||||
try { | 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) { | } catch (Exception e) { | ||||
e.printStackTrace(); | e.printStackTrace(); | ||||
@@ -64,7 +47,7 @@ public enum ContractDeployExeUtil { | |||||
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | ||||
pub = contractKeyPair.getPubKey(); | pub = contractKeyPair.getPubKey(); | ||||
}else { | }else { | ||||
pub = KeyGenCommand.readPubKey(pubPath); | |||||
pub = KeyGenUtils.readPubKey(pubPath); | |||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
@@ -111,6 +94,8 @@ public enum ContractDeployExeUtil { | |||||
DataContractRegistry.register(ContractEventSendOperation.class); | DataContractRegistry.register(ContractEventSendOperation.class); | ||||
DataContractRegistry.register(DataAccountRegisterOperation.class); | DataContractRegistry.register(DataAccountRegisterOperation.class); | ||||
DataContractRegistry.register(UserRegisterOperation.class); | DataContractRegistry.register(UserRegisterOperation.class); | ||||
DataContractRegistry.register(ParticipantRegisterOperation.class); | |||||
DataContractRegistry.register(ParticipantStateUpdateOperation.class); | |||||
} | } | ||||
public BlockchainService initBcsrv(String host, int port) { | public BlockchainService initBcsrv(String host, int port) { | ||||
@@ -1,10 +1,10 @@ | |||||
package com.jd.blockchain; | package com.jd.blockchain; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | import com.jd.blockchain.crypto.PrivKey; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.utils.StringUtils; | import com.jd.blockchain.utils.StringUtils; | ||||
import com.jd.blockchain.utils.codec.Base58Utils; | import com.jd.blockchain.utils.codec.Base58Utils; | ||||
import com.jd.blockchain.utils.io.FileUtils; | import com.jd.blockchain.utils.io.FileUtils; | ||||
@@ -102,8 +102,8 @@ public class ContractDeployMojo extends AbstractMojo { | |||||
byte[] contractBytes = FileUtils.readBytes(contractPath); | 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); | BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv); | ||||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | ||||
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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)); | |||||
} | |||||
} |
@@ -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>"; | |||||
} |
@@ -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 + | |||||
'}'; | |||||
} | |||||
} |
@@ -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 + | |||||
'}'; | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} | |||||
} | |||||
@@ -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); | |||||
} | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} | |||||
@@ -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; | |||||
} | |||||
} |
@@ -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(); | |||||
} | |||||
} |
@@ -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 |
@@ -1 +0,0 @@ | |||||
blacklist=java.io,java.net,java.util.Random |
@@ -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/* |
@@ -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 |
@@ -0,0 +1,3 @@ | |||||
com.jd.blockchain.* | |||||
java.nio.charset.Charset | |||||
com.alibaba.fastjson.* |
@@ -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(); | |||||
} | |||||
} |
@@ -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); | |||||
// } | |||||
//} |
@@ -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()); | |||||
// } | |||||
//} |
@@ -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(); | |||||
// } | |||||
//} |
@@ -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; | |||||
// } | |||||
//} |
@@ -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/" ); | |||||
// } | |||||
//} |
@@ -27,6 +27,12 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
<scope>provided</scope> | <scope>provided</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.alibaba</groupId> | |||||
<artifactId>fastjson</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -34,11 +40,11 @@ | |||||
<plugin> | <plugin> | ||||
<artifactId>maven-assembly-plugin</artifactId> | <artifactId>maven-assembly-plugin</artifactId> | ||||
<configuration> | <configuration> | ||||
<finalName>random</finalName> | |||||
<finalName>complex</finalName> | |||||
<appendAssemblyId>false</appendAssemblyId> | <appendAssemblyId>false</appendAssemblyId> | ||||
<archive> | <archive> | ||||
<manifest> | <manifest> | ||||
<mainClass>com.jd.blockchain.contract.RandomContractImpl</mainClass> | |||||
<mainClass>com.jd.blockchain.contract.ComplexContractImpl</mainClass> | |||||
</manifest> | </manifest> | ||||
</archive> | </archive> | ||||
<descriptorRefs> | <descriptorRefs> | ||||
@@ -0,0 +1,7 @@ | |||||
package com.jd.blockchain.contract; | |||||
@Contract | |||||
public interface ComplexContract { | |||||
@ContractEvent(name = "read-key") | |||||
String read(String address, String key); | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -7,6 +7,8 @@ import org.bouncycastle.crypto.CipherParameters; | |||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | ||||
import org.bouncycastle.crypto.params.*; | import org.bouncycastle.crypto.params.*; | ||||
import org.bouncycastle.crypto.signers.ECDSASigner; | 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.ECCurve; | ||||
import org.bouncycastle.math.ec.ECMultiplier; | import org.bouncycastle.math.ec.ECMultiplier; | ||||
import org.bouncycastle.math.ec.ECPoint; | 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 | // 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. | // 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----------------- | //-----------------Key Generation Algorithm----------------- | ||||
@@ -0,0 +1,20 @@ | |||||
package com.jd.blockchain; | |||||
import static org.junit.Assert.assertTrue; | |||||
import org.junit.Test; | |||||
/** | |||||
* Unit test for simple App. | |||||
*/ | |||||
public class AppTest | |||||
{ | |||||
/** | |||||
* Rigorous Test :-) | |||||
*/ | |||||
@Test | |||||
public void shouldAnswerWithTrue() | |||||
{ | |||||
assertTrue( true ); | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -16,6 +16,9 @@ import org.bouncycastle.util.encoders.Base64; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.security.*; | import java.security.*; | ||||
import java.security.spec.InvalidKeySpecException; | |||||
import java.security.spec.PKCS8EncodedKeySpec; | |||||
import java.security.spec.X509EncodedKeySpec; | |||||
/** | /** | ||||
* @author zhanglin33 | * @author zhanglin33 | ||||
@@ -25,16 +28,18 @@ import java.security.*; | |||||
*/ | */ | ||||
public class CSRBuilder { | public class CSRBuilder { | ||||
private String BC = BouncyCastleProvider.PROVIDER_NAME; | |||||
private final String BC = BouncyCastleProvider.PROVIDER_NAME; | |||||
private PublicKey pubKey; | private PublicKey pubKey; | ||||
private PrivateKey privKey; | private PrivateKey privKey; | ||||
private String algoName; | private String algoName; | ||||
private int keyLength; | |||||
public void init() { | public void init() { | ||||
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | ||||
algoName = "SHA1withRSA"; | algoName = "SHA1withRSA"; | ||||
keyLength = 2048; | |||||
KeyPairGenerator generator; | KeyPairGenerator generator; | ||||
try { | try { | ||||
generator = KeyPairGenerator.getInstance("RSA", BC); | 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()); | Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); | ||||
this.algoName = algoName; | |||||
this.algoName = algoName; | |||||
this.keyLength = keyLength; | |||||
KeyPairGenerator generator; | KeyPairGenerator generator; | ||||
KeyPair keyPair; | KeyPair keyPair; | ||||
@@ -60,34 +66,69 @@ public class CSRBuilder { | |||||
switch (hashAndSignature[1]) { | switch (hashAndSignature[1]) { | ||||
case "RSA": { | case "RSA": { | ||||
generator = KeyPairGenerator.getInstance("RSA", BC); | generator = KeyPairGenerator.getInstance("RSA", BC); | ||||
generator.initialize(KeyLength); | |||||
keyPair = generator.generateKeyPair(); | |||||
pubKey = keyPair.getPublic(); | |||||
privKey = keyPair.getPrivate(); | |||||
generator.initialize(keyLength); | |||||
break; | break; | ||||
} | } | ||||
case "SM2": { | case "SM2": { | ||||
generator = KeyPairGenerator.getInstance("EC", BC); | generator = KeyPairGenerator.getInstance("EC", BC); | ||||
if (KeyLength != 256) { | |||||
if (keyLength != 256) { | |||||
throw new CryptoException("SM3withSM2 with unsupported key length [" + | throw new CryptoException("SM3withSM2 with unsupported key length [" + | ||||
KeyLength +"] in CSR!"); | |||||
keyLength +"] in CSR!"); | |||||
} | } | ||||
generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); | ||||
keyPair = generator.generateKeyPair(); | |||||
pubKey = keyPair.getPublic(); | |||||
privKey = keyPair.getPrivate(); | |||||
break; | break; | ||||
} | } | ||||
default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" + | 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) { | } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | ||||
throw new CryptoException(e.getMessage(), 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, | public String buildRequest(String countryName, String stateName, String cityName, | ||||
String organizationName, String departmentName, String domainName, | String organizationName, String departmentName, String domainName, | ||||
String emailName) { | String emailName) { | ||||
@@ -126,4 +167,12 @@ public class CSRBuilder { | |||||
public PrivateKey getPrivKey() { | public PrivateKey getPrivKey() { | ||||
return privKey; | return privKey; | ||||
} | } | ||||
public String getAlgoName() { | |||||
return algoName; | |||||
} | |||||
public int getKeyLength() { | |||||
return keyLength; | |||||
} | |||||
} | } |
@@ -25,6 +25,7 @@ public class CertParser { | |||||
private String sigAlgName; | private String sigAlgName; | ||||
private String userName; | private String userName; | ||||
private String issuerName; | private String issuerName; | ||||
private int keyLength; | |||||
private Date startTime; | private Date startTime; | ||||
private Date endTime; | private Date endTime; | ||||
@@ -71,6 +72,17 @@ public class CertParser { | |||||
sigAlgName = userCert.getSigAlgName(); | sigAlgName = userCert.getSigAlgName(); | ||||
issuerName = userCert.getIssuerX500Principal().getName(); | issuerName = userCert.getIssuerX500Principal().getName(); | ||||
userName = userCert.getSubjectX500Principal().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 | // certificate string in Base64 format | ||||
@@ -121,6 +133,10 @@ public class CertParser { | |||||
return issuerName; | return issuerName; | ||||
} | } | ||||
public int getKeyLength() { | |||||
return keyLength; | |||||
} | |||||
public Date getStartTime() { | public Date getStartTime() { | ||||
return startTime; | return startTime; | ||||
} | } | ||||
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | 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 com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.*; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.*; | import static com.jd.blockchain.crypto.CryptoAlgorithm.*; | ||||
@@ -125,4 +129,145 @@ public class SHA1WITHRSA2048SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | 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)); | |||||
} | |||||
} | } |
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | 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 com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.PublicKey; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | ||||
@@ -125,4 +129,186 @@ public class SHA1WITHRSA4096SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | 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)); | |||||
} | |||||
} | } |
@@ -1,9 +1,13 @@ | |||||
package com.jd.blockchain.crypto.service.pki; | package com.jd.blockchain.crypto.service.pki; | ||||
import com.jd.blockchain.crypto.*; | 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 com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.bouncycastle.util.encoders.Hex; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.security.PublicKey; | |||||
import java.util.Random; | import java.util.Random; | ||||
import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY; | ||||
@@ -270,4 +274,80 @@ public class SM3WITHSM2SignatureFunctionTest { | |||||
resolvedSignatureDigest.getAlgorithm()); | resolvedSignatureDigest.getAlgorithm()); | ||||
assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes()); | 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)); | |||||
} | |||||
} | } |
@@ -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"; | 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); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||||
assertEquals("SHA1WITHRSA", parser.getSigAlgName()); | |||||
assertEquals(2048, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @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=="; | 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); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SHA1WITHRSA",parser.getSigAlgName()); | |||||
assertEquals("SHA1WITHRSA", parser.getSigAlgName()); | |||||
assertEquals(4096, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -103,7 +105,8 @@ public class CertParserTest { | |||||
String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq"; | String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq"; | ||||
parser.parse(userCert, issuerCert); | parser.parse(userCert, issuerCert); | ||||
assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||||
assertEquals("SM3WITHSM2", parser.getSigAlgName()); | |||||
assertEquals(256, parser.getKeyLength()); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -141,6 +144,7 @@ public class CertParserTest { | |||||
"PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | "PrIDl+E4aL3FypntFXHG3T+Keg==\n" + | ||||
"-----END CERTIFICATE-----"; | "-----END CERTIFICATE-----"; | ||||
parser.parse(issuerCert, CACert); | parser.parse(issuerCert, CACert); | ||||
assertEquals("SM3WITHSM2",parser.getSigAlgName()); | |||||
assertEquals("SM3WITHSM2", parser.getSigAlgName()); | |||||
assertEquals(256, parser.getKeyLength()); | |||||
} | } | ||||
} | } |
@@ -13,6 +13,8 @@ import org.bouncycastle.crypto.engines.SM2Engine; | |||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | import org.bouncycastle.crypto.generators.ECKeyPairGenerator; | ||||
import org.bouncycastle.crypto.params.*; | import org.bouncycastle.crypto.params.*; | ||||
import org.bouncycastle.crypto.signers.SM2Signer; | import org.bouncycastle.crypto.signers.SM2Signer; | ||||
import org.bouncycastle.jce.ECNamedCurveTable; | |||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; | |||||
import org.bouncycastle.math.ec.*; | import org.bouncycastle.math.ec.*; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -29,19 +31,10 @@ public class SM2Utils { | |||||
// The length of sm3 output is 32 bytes | // The length of sm3 output is 32 bytes | ||||
private static final int SM3DIGEST_LENGTH = 32; | 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----------------- | //-----------------Key Generation Algorithm----------------- | ||||
@@ -0,0 +1,20 @@ | |||||
package com.jd.blockchain; | |||||
import static org.junit.Assert.assertTrue; | |||||
import org.junit.Test; | |||||
/** | |||||
* Unit test for simple App. | |||||
*/ | |||||
public class AppTest | |||||
{ | |||||
/** | |||||
* Rigorous Test :-) | |||||
*/ | |||||
@Test | |||||
public void shouldAnswerWithTrue() | |||||
{ | |||||
assertTrue( true ); | |||||
} | |||||
} |
@@ -23,10 +23,7 @@ public class GatewayBooter { | |||||
} | } | ||||
private static final void writePID() throws Exception { | 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"); | String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | ||||
if (currPath.contains("!/")) { | if (currPath.contains("!/")) { | ||||
currPath = currPath.substring(5, currPath.indexOf("!/")); | currPath = currPath.substring(5, currPath.indexOf("!/")); | ||||
@@ -40,6 +37,10 @@ public class GatewayBooter { | |||||
String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; | String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; | ||||
File pidFile = new File(pidFilePath); | File pidFile = new File(pidFilePath); | ||||
if (!pidFile.exists()) { | if (!pidFile.exists()) { | ||||
File dir = pidFile.getParentFile(); | |||||
if (!dir.exists()) { | |||||
dir.mkdirs(); | |||||
} | |||||
pidFile.createNewFile(); | pidFile.createNewFile(); | ||||
} | } | ||||
String name = ManagementFactory.getRuntimeMXBean().getName(); | String name = ManagementFactory.getRuntimeMXBean().getName(); | ||||
@@ -5,5 +5,5 @@ GATEWAY=$(ls $HOME/lib | grep deployment-gateway-) | |||||
if [ ! -n "$GATEWAY" ]; then | if [ ! -n "$GATEWAY" ]; then | ||||
echo "GateWay Is Null !!!" | echo "GateWay Is Null !!!" | ||||
else | else | ||||
nohup java -jar -server $HOME/lib/$GATEWAY -c $HOME/config/gateway.conf $* > gw.out 2>&1 & | |||||
nohup java -jar -server -Dgateway.log=$HOME $HOME/lib/$GATEWAY -c $HOME/config/gateway.conf $* >$HOME/bin/gw.out 2>&1 & | |||||
fi | fi |
@@ -25,7 +25,11 @@ | |||||
<artifactId>runtime-modular-booter</artifactId> | <artifactId>runtime-modular-booter</artifactId> | ||||
<version>${project.version}</version> | <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> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>storage-composite</artifactId> | <artifactId>storage-composite</artifactId> | ||||
@@ -55,6 +55,16 @@ | |||||
<exclude>com.jd.blockchain:deployment-peer</exclude> | <exclude>com.jd.blockchain:deployment-peer</exclude> | ||||
</excludes> | </excludes> | ||||
</dependencySet> | </dependencySet> | ||||
<!--<dependencySet> | |||||
<unpack>false</unpack> | |||||
<useProjectArtifact>true</useProjectArtifact> | |||||
<outputDirectory>ext</outputDirectory> | |||||
<includes> | |||||
<include>com.jd.blockchain:ump-booter</include> | |||||
</includes> | |||||
</dependencySet>--> | |||||
</dependencySets> | </dependencySets> | ||||
<moduleSets> | <moduleSets> | ||||
@@ -7,6 +7,48 @@ ledger.name= | |||||
#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 | #声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 | ||||
created-time=2019-08-01 14:26:58.069+0800 | created-time=2019-08-01 14:26:58.069+0800 | ||||
#----------------------------------------------- | |||||
# 初始的角色名称列表;可选项; | |||||
# 角色名称不区分大小写,最长不超过20个字符;多个角色名称之间用半角的逗点“,”分隔; | |||||
# 系统会预置一个默认角色“DEFAULT”,所有未指定角色的用户都以赋予该角色的权限;若初始化时未配置默认角色的权限,则为默认角色分配所有权限; | |||||
# | |||||
# 注:如果声明了角色,但未声明角色对应的权限清单,这会忽略该角色的初始化; | |||||
# | |||||
#security.roles=DEFAULT, ADMIN, MANAGER, GUEST | |||||
# 赋予角色的账本权限清单;可选项; | |||||
# 可选的权限如下; | |||||
# AUTHORIZE_ROLES, SET_CONSENSUS, SET_CRYPTO, REGISTER_PARTICIPANT, | |||||
# REGISTER_USER, REGISTER_DATA_ACCOUNT, REGISTER_CONTRACT, UPGRADE_CONTRACT, | |||||
# SET_USER_ATTRIBUTES, WRITE_DATA_ACCOUNT, | |||||
# APPROVE_TX, CONSENSUS_TX | |||||
# 多项权限之间用逗点“,”分隔; | |||||
# | |||||
#security.role.DEFAULT.ledger-privileges=REGISTER_USER, REGISTER_DATA_ACCOUNT | |||||
# 赋予角色的交易权限清单;可选项; | |||||
# 可选的权限如下; | |||||
# DIRECT_OPERATION, CONTRACT_OPERATION | |||||
# 多项权限之间用逗点“,”分隔; | |||||
# | |||||
#security.role.DEFAULT.tx-privileges=DIRECT_OPERATION, CONTRACT_OPERATION | |||||
# 其它角色的配置示例; | |||||
# 系统管理员角色:只能操作全局性的参数配置和用户注册,只能执行直接操作指令; | |||||
#security.role.ADMIN.ledger-privileges=CONFIGURE_ROLES, AUTHORIZE_USER_ROLES, SET_CONSENSUS, SET_CRYPTO, REGISTER_PARTICIPANT, REGISTER_USER | |||||
#security.role.ADMIN.tx-privileges=DIRECT_OPERATION | |||||
# 业务主管角色:只能够执行账本数据相关的操作,包括注册用户、注册数据账户、注册合约、升级合约、写入数据等;能够执行直接操作指令和调用合约; | |||||
#security.role.MANAGER.ledger-privileges=CONFIGURE_ROLES, AUTHORIZE_USER_ROLES, REGISTER_USER, REGISTER_DATA_ACCOUNT, REGISTER_CONTRACT, UPGRADE_CONTRACT, SET_USER_ATTRIBUTES, WRITE_DATA_ACCOUNT, | |||||
#security.role.MANAGER.tx-privileges=DIRECT_OPERATION, CONTRACT_OPERATION | |||||
# 访客角色:不具备任何的账本权限,只有数据读取的操作;也只能够通过调用合约来读取数据; | |||||
#security.role.GUEST.ledger-privileges= | |||||
#security.role.GUEST.tx-privileges=CONTRACT_OPERATION | |||||
#----------------------------------------------- | |||||
#共识服务提供者;必须; | #共识服务提供者;必须; | ||||
consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | ||||
@@ -17,16 +59,36 @@ consensus.conf=bftsmart.config | |||||
crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ | crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ | ||||
com.jd.blockchain.crypto.service.sm.SMCryptoService | com.jd.blockchain.crypto.service.sm.SMCryptoService | ||||
#从存储中加载账本数据时,是否校验哈希;可选; | |||||
crypto.verify-hash=true | |||||
#哈希算法; | |||||
crypto.hash-algorithm=SHA256 | |||||
#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | #参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | ||||
cons_parti.count=4 | cons_parti.count=4 | ||||
#--------------------- | |||||
#第0个参与方的名称; | #第0个参与方的名称; | ||||
cons_parti.0.name= | cons_parti.0.name= | ||||
#第0个参与方的公钥文件路径; | #第0个参与方的公钥文件路径; | ||||
cons_parti.0.pubkey-path= | cons_parti.0.pubkey-path= | ||||
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.0.pubkey= | cons_parti.0.pubkey= | ||||
#第0个参与方的角色清单;可选项; | |||||
#cons_parti.0.roles=ADMIN, MANAGER | |||||
#第0个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
#cons_parti.0.roles-policy=UNION | |||||
#第0个参与方的共识服务的主机地址; | |||||
cons_parti.0.consensus.host=127.0.0.1 | |||||
#第0个参与方的共识服务的端口; | |||||
cons_parti.0.consensus.port=8900 | |||||
#第0个参与方的共识服务是否开启安全连接; | |||||
cons_parti.0.consensus.secure=true | |||||
#第0个参与方的账本初始服务的主机; | #第0个参与方的账本初始服务的主机; | ||||
cons_parti.0.initializer.host=127.0.0.1 | cons_parti.0.initializer.host=127.0.0.1 | ||||
#第0个参与方的账本初始服务的端口; | #第0个参与方的账本初始服务的端口; | ||||
@@ -34,12 +96,27 @@ cons_parti.0.initializer.port=8800 | |||||
#第0个参与方的账本初始服务是否开启安全连接; | #第0个参与方的账本初始服务是否开启安全连接; | ||||
cons_parti.0.initializer.secure=false | cons_parti.0.initializer.secure=false | ||||
#--------------------- | |||||
#第1个参与方的名称; | #第1个参与方的名称; | ||||
cons_parti.1.name= | cons_parti.1.name= | ||||
#第1个参与方的公钥文件路径; | #第1个参与方的公钥文件路径; | ||||
cons_parti.1.pubkey-path= | cons_parti.1.pubkey-path= | ||||
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.1.pubkey= | cons_parti.1.pubkey= | ||||
#第1个参与方的角色清单;可选项; | |||||
#cons_parti.1.roles=MANAGER | |||||
#第1个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
#cons_parti.1.roles-policy=UNION | |||||
#第1个参与方的共识服务的主机地址; | |||||
cons_parti.1.consensus.host=127.0.0.1 | |||||
#第1个参与方的共识服务的端口; | |||||
cons_parti.1.consensus.port=8910 | |||||
#第1个参与方的共识服务是否开启安全连接; | |||||
cons_parti.1.consensus.secure=false | |||||
#第1个参与方的账本初始服务的主机; | #第1个参与方的账本初始服务的主机; | ||||
cons_parti.1.initializer.host=127.0.0.1 | cons_parti.1.initializer.host=127.0.0.1 | ||||
#第1个参与方的账本初始服务的端口; | #第1个参与方的账本初始服务的端口; | ||||
@@ -47,12 +124,26 @@ cons_parti.1.initializer.port=8810 | |||||
#第1个参与方的账本初始服务是否开启安全连接; | #第1个参与方的账本初始服务是否开启安全连接; | ||||
cons_parti.1.initializer.secure=false | cons_parti.1.initializer.secure=false | ||||
#--------------------- | |||||
#第2个参与方的名称; | #第2个参与方的名称; | ||||
cons_parti.2.name= | cons_parti.2.name= | ||||
#第2个参与方的公钥文件路径; | #第2个参与方的公钥文件路径; | ||||
cons_parti.2.pubkey-path= | cons_parti.2.pubkey-path= | ||||
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.2.pubkey= | cons_parti.2.pubkey= | ||||
#第2个参与方的角色清单;可选项; | |||||
#cons_parti.2.roles=MANAGER | |||||
#第2个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
#cons_parti.2.roles-policy=UNION | |||||
#第2个参与方的共识服务的主机地址; | |||||
cons_parti.2.consensus.host=127.0.0.1 | |||||
#第2个参与方的共识服务的端口; | |||||
cons_parti.2.consensus.port=8920 | |||||
#第2个参与方的共识服务是否开启安全连接; | |||||
cons_parti.2.consensus.secure=false | |||||
#第2个参与方的账本初始服务的主机; | #第2个参与方的账本初始服务的主机; | ||||
cons_parti.2.initializer.host=127.0.0.1 | cons_parti.2.initializer.host=127.0.0.1 | ||||
#第2个参与方的账本初始服务的端口; | #第2个参与方的账本初始服务的端口; | ||||
@@ -60,12 +151,26 @@ cons_parti.2.initializer.port=8820 | |||||
#第2个参与方的账本初始服务是否开启安全连接; | #第2个参与方的账本初始服务是否开启安全连接; | ||||
cons_parti.2.initializer.secure=false | cons_parti.2.initializer.secure=false | ||||
#--------------------- | |||||
#第3个参与方的名称; | #第3个参与方的名称; | ||||
cons_parti.3.name= | cons_parti.3.name= | ||||
#第3个参与方的公钥文件路径; | #第3个参与方的公钥文件路径; | ||||
cons_parti.3.pubkey-path= | cons_parti.3.pubkey-path= | ||||
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.3.pubkey= | cons_parti.3.pubkey= | ||||
#第3个参与方的角色清单;可选项; | |||||
#cons_parti.3.roles=GUEST | |||||
#第3个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
#cons_parti.3.roles-policy=INTERSECT | |||||
#第3个参与方的共识服务的主机地址; | |||||
cons_parti.3.consensus.host=127.0.0.1 | |||||
#第3个参与方的共识服务的端口; | |||||
cons_parti.3.consensus.port=8930 | |||||
#第3个参与方的共识服务是否开启安全连接; | |||||
cons_parti.3.consensus.secure=false | |||||
#第3个参与方的账本初始服务的主机; | #第3个参与方的账本初始服务的主机; | ||||
cons_parti.3.initializer.host=127.0.0.1 | cons_parti.3.initializer.host=127.0.0.1 | ||||
#第3个参与方的账本初始服务的端口; | #第3个参与方的账本初始服务的端口; | ||||
@@ -12,5 +12,5 @@ else | |||||
else | else | ||||
echo "keys file will be saved $HOME/config/keys" | echo "keys file will be saved $HOME/config/keys" | ||||
fi | fi | ||||
java -jar $HOME/libs/$boot_file -o $HOME/config/keys -l $HOME/config/init/local.conf $* | |||||
java -jar $HOME/libs/$boot_file -o $HOME/config/keys $* | |||||
fi | fi |
@@ -5,5 +5,5 @@ boot_file=$(ls $HOME/libs | grep tools-initializer-booter-) | |||||
if [ ! -n "$boot_file" ]; then | if [ ! -n "$boot_file" ]; then | ||||
echo "tools-initializer-booter is null" | echo "tools-initializer-booter is null" | ||||
else | else | ||||
java -jar $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* | |||||
fi | |||||
java -jar -server -Dinit.log=$HOME $HOME/libs/$boot_file -l $HOME/config/init/local.conf -i $HOME/config/init/ledger.init $* | |||||
fi |
@@ -0,0 +1,9 @@ | |||||
#!/bin/bash | |||||
HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
UMP=$(ls $HOME/ext | grep ump-booter-) | |||||
if [ ! -n "UMP" ]; then | |||||
echo "Unified Management Platform Is Null !!!" | |||||
else | |||||
nohup java -jar -server -Djump.log=$HOME $HOME/ext/$UMP -p 8000 $* >$HOME/bin/jump.out 2>&1 & | |||||
fi |
@@ -0,0 +1,16 @@ | |||||
#!/bin/bash | |||||
#启动Home路径 | |||||
BOOT_HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
#获取进程PID | |||||
PID=`ps -ef | grep $BOOT_HOME/ext/ump-booter | grep -v grep | awk '{print $2}'` | |||||
#通过Kill命令将进程杀死 | |||||
if [ -z "$PID" ]; then | |||||
echo "Unable to find UMP PID. stop aborted." | |||||
else | |||||
echo "Start to kill PID = $PID ..." | |||||
kill -9 $PID | |||||
echo "Unified Management Platform has been stopped ..." | |||||
fi |
@@ -0,0 +1,9 @@ | |||||
#!/bin/bash | |||||
HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
PEER=$(ls $HOME/system | grep deployment-peer-) | |||||
if [ ! -n "$PEER" ]; then | |||||
echo "Peer Is Null !!!" | |||||
else | |||||
nohup java -jar -server -Xmx512m -Xms512m -Dpeer.log=$HOME $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* >$HOME/bin/peer.out 2>&1 & | |||||
fi |
@@ -1,9 +0,0 @@ | |||||
#!/bin/bash | |||||
HOME=$(cd `dirname $0`;cd ../; pwd) | |||||
PEER=$(ls $HOME/system | grep deployment-peer-) | |||||
if [ ! -n "$PEER" ]; then | |||||
echo "Peer Is Null !!!" | |||||
else | |||||
nohup java -jar -server -Xmx2g -Xms2g $HOME/system/$PEER -home=$HOME -c $HOME/config/ledger-binding.conf -p 7080 $* & | |||||
fi |
@@ -75,24 +75,6 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>commons-io</groupId> | <groupId>commons-io</groupId> | ||||
<artifactId>commons-io</artifactId> | <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> | ||||
<dependency> | <dependency> | ||||
@@ -110,7 +92,7 @@ | |||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
<artifactId>spring-boot-starter-log4j2</artifactId> | <artifactId>spring-boot-starter-log4j2</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>org.springframework.boot</groupId> | <groupId>org.springframework.boot</groupId> | ||||
<artifactId>spring-boot-starter-security</artifactId> | <artifactId>spring-boot-starter-security</artifactId> | ||||
@@ -2,31 +2,36 @@ package com.jd.blockchain.gateway; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.URL; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||||
import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
import org.springframework.context.ConfigurableApplicationContext; | import org.springframework.context.ConfigurableApplicationContext; | ||||
import org.springframework.core.io.ClassPathResource; | import org.springframework.core.io.ClassPathResource; | ||||
import com.jd.blockchain.crypto.AsymmetricKeypair; | import com.jd.blockchain.crypto.AsymmetricKeypair; | ||||
import com.jd.blockchain.crypto.KeyGenUtils; | |||||
import com.jd.blockchain.crypto.PrivKey; | import com.jd.blockchain.crypto.PrivKey; | ||||
import com.jd.blockchain.crypto.PubKey; | 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; | ||||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||||
import com.jd.blockchain.utils.BaseConstant; | import com.jd.blockchain.utils.BaseConstant; | ||||
import com.jd.blockchain.utils.ConsoleUtils; | import com.jd.blockchain.utils.ConsoleUtils; | ||||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||||
public class GatewayServerBooter { | public class GatewayServerBooter { | ||||
private static final String DEFAULT_GATEWAY_PROPS = "application-gw.properties"; | |||||
// 当前参与方在初始化配置中的参与方列表的编号; | // 当前参与方在初始化配置中的参与方列表的编号; | ||||
private static final String HOST_ARG = "-c"; | private static final String HOST_ARG = "-c"; | ||||
//sp;针对spring.config.location这个参数进行包装; | //sp;针对spring.config.location这个参数进行包装; | ||||
private static final String SPRING_CF_LOCATION = BaseConstant.SPRING_CF_LOCATION; | private static final String SPRING_CF_LOCATION = BaseConstant.SPRING_CF_LOCATION; | ||||
// 是否输出调试信息; | // 是否输出调试信息; | ||||
private static final String DEBUG_OPT = "-debug"; | private static final String DEBUG_OPT = "-debug"; | ||||
@@ -57,11 +62,20 @@ public class GatewayServerBooter { | |||||
}else { | }else { | ||||
//if no the config file, then should tip as follows. but it's not a good feeling, so we create it by inputStream; | //if no the config file, then should tip as follows. but it's not a good feeling, so we create it by inputStream; | ||||
ConsoleUtils.info("no param:-sp, format: -sp /x/xx.properties, use the default application-gw.properties "); | ConsoleUtils.info("no param:-sp, format: -sp /x/xx.properties, use the default application-gw.properties "); | ||||
ClassPathResource configResource = new ClassPathResource("application-gw.properties"); | |||||
ClassPathResource configResource = new ClassPathResource(DEFAULT_GATEWAY_PROPS); | |||||
InputStream in = configResource.getInputStream(); | InputStream in = configResource.getInputStream(); | ||||
File targetFile = new File(System.getProperty("user.dir")+File.separator+"conf"+File.separator+"application-gw.properties"); | |||||
// 将文件写入至config目录下 | |||||
String configPath = bootPath() + "config" + File.separator + DEFAULT_GATEWAY_PROPS; | |||||
File targetFile = new File(configPath); | |||||
// 先将原来文件删除再Copy | |||||
if (targetFile.exists()) { | |||||
FileUtils.forceDelete(targetFile); | |||||
} | |||||
FileUtils.copyInputStreamToFile(in, targetFile); | FileUtils.copyInputStreamToFile(in, targetFile); | ||||
springConfigLocation = "file:"+targetFile.getAbsolutePath(); | |||||
springConfigLocation = "file:" + targetFile.getAbsolutePath(); | |||||
} | } | ||||
// 启动服务器; | // 启动服务器; | ||||
@@ -88,19 +102,19 @@ public class GatewayServerBooter { | |||||
String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | ||||
if (base58Pwd == null || base58Pwd.length() == 0) { | 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; | PrivKey privKey = null; | ||||
String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | ||||
if (base58PrivKey == null) { | if (base58PrivKey == null) { | ||||
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | //注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | ||||
privKey = KeyGenCommand.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||||
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||||
} else { | } else { | ||||
privKey = KeyGenCommand.decodePrivKey(base58PrivKey, base58Pwd); | |||||
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd); | |||||
} | } | ||||
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | ||||
} | } | ||||
@@ -147,4 +161,17 @@ public class GatewayServerBooter { | |||||
return appCtx; | return appCtx; | ||||
} | } | ||||
private static String bootPath() throws Exception { | |||||
URL url = GatewayServerBooter.class.getProtectionDomain().getCodeSource().getLocation(); | |||||
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | |||||
// 处理打包至SpringBoot问题 | |||||
if (currPath.contains("!/")) { | |||||
currPath = currPath.substring(5, currPath.indexOf("!/")); | |||||
} | |||||
if (currPath.endsWith(".jar")) { | |||||
currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); | |||||
} | |||||
System.out.printf("Current Project Boot Path = %s \r\n", currPath); | |||||
return new File(currPath).getParent() + File.separator; | |||||
} | |||||
} | } |
@@ -0,0 +1,8 @@ | |||||
package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | |||||
public interface GatewayInterceptService { | |||||
void intercept(TransactionRequest txRequest); | |||||
} |
@@ -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()); | |||||
} | |||||
} |
@@ -3,8 +3,7 @@ package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.sdk.ContractSettings; | import com.jd.blockchain.sdk.ContractSettings; | ||||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.sdk.LedgerBaseSettings; | |||||
/** | /** | ||||
* queryService only for gateway; | * queryService only for gateway; | ||||
@@ -35,7 +34,7 @@ public interface GatewayQueryService { | |||||
* 账本Hash | * 账本Hash | ||||
* @return | * @return | ||||
*/ | */ | ||||
LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash); | |||||
LedgerBaseSettings getLedgerBaseSettings(HashDigest ledgerHash); | |||||
/** | /** | ||||
* 获取账本指定合约信息 | * 获取账本指定合约信息 | ||||
@@ -3,18 +3,17 @@ package com.jd.blockchain.gateway.service; | |||||
import com.jd.blockchain.consensus.ConsensusProvider; | import com.jd.blockchain.consensus.ConsensusProvider; | ||||
import com.jd.blockchain.consensus.ConsensusProviders; | import com.jd.blockchain.consensus.ConsensusProviders; | ||||
import com.jd.blockchain.consensus.ConsensusSettings; | 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.crypto.HashDigest; | ||||
import com.jd.blockchain.gateway.PeerService; | 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.ContractInfo; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||||
import com.jd.blockchain.ledger.LedgerMetadata; | import com.jd.blockchain.ledger.LedgerMetadata; | ||||
import com.jd.blockchain.ledger.ParticipantNode; | import com.jd.blockchain.ledger.ParticipantNode; | ||||
import com.jd.blockchain.sdk.ContractSettings; | import com.jd.blockchain.sdk.ContractSettings; | ||||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||||
import com.jd.blockchain.sdk.LedgerBaseSettings; | |||||
import com.jd.blockchain.utils.QueryUtil; | import com.jd.blockchain.utils.QueryUtil; | ||||
import com.jd.blockchain.utils.codec.HexUtils; | 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.beans.factory.annotation.Autowired; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import java.util.Arrays; | import java.util.Arrays; | ||||
@@ -32,28 +31,26 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
@Override | @Override | ||||
public HashDigest[] getLedgersHash(int fromIndex, int count) { | public HashDigest[] getLedgersHash(int fromIndex, int count) { | ||||
HashDigest ledgersHash[] = peerService.getQueryService().getLedgerHashs(); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,ledgersHash.length); | |||||
HashDigest ledgersHashNew[] = Arrays.copyOfRange(ledgersHash,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return ledgersHashNew; | |||||
HashDigest[] ledgersHashs = peerService.getQueryService().getLedgerHashs(); | |||||
int[] indexAndCount = QueryUtil.calFromIndexAndCount(fromIndex, count, ledgersHashs.length); | |||||
return Arrays.copyOfRange(ledgersHashs, indexAndCount[0], indexAndCount[0] + indexAndCount[1]); | |||||
} | } | ||||
@Override | @Override | ||||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | ||||
ParticipantNode participantNode[] = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,participantNode.length); | |||||
ParticipantNode participantNodesNew[] = Arrays.copyOfRange(participantNode,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||||
return participantNodesNew; | |||||
ParticipantNode[] participantNodes = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
int[] indexAndCount = QueryUtil.calFromIndexAndCount(fromIndex, count, participantNodes.length); | |||||
ParticipantNode[] participantNodesNews = Arrays.copyOfRange(participantNodes, indexAndCount[0], | |||||
indexAndCount[0] + indexAndCount[1]); | |||||
return participantNodesNews; | |||||
} | } | ||||
@Override | @Override | ||||
public LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash) { | |||||
ParticipantNode[] participantNodes = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||||
public LedgerBaseSettings getLedgerBaseSettings(HashDigest ledgerHash) { | |||||
LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash); | |||||
LedgerAdminInfo ledgerAdminInfo = peerService.getQueryService().getLedgerAdminInfo(ledgerHash); | |||||
return initLedgerInitSettings(participantNodes, ledgerMetadata); | |||||
return initLedgerBaseSettings(ledgerAdminInfo); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -72,36 +69,38 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
} | } | ||||
/** | /** | ||||
* 初始化账本配置 | |||||
* 初始化账本的基本配置 | |||||
* | |||||
* @param ledgerAdminInfo | |||||
* 账本信息 | |||||
* | * | ||||
* @param participantNodes | |||||
* 参与方列表 | |||||
* @param ledgerMetadata | |||||
* 账本元数据 | |||||
* @return | * @return | ||||
*/ | */ | ||||
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata) { | |||||
LedgerInitSettings ledgerInitSettings = new LedgerInitSettings(); | |||||
private LedgerBaseSettings initLedgerBaseSettings(LedgerAdminInfo ledgerAdminInfo) { | |||||
LedgerMetadata ledgerMetadata = ledgerAdminInfo.getMetadata(); | |||||
LedgerBaseSettings ledgerBaseSettings = new LedgerBaseSettings(); | |||||
// 设置参与方 | // 设置参与方 | ||||
ledgerInitSettings.setParticipantNodes(participantNodes); | |||||
ledgerBaseSettings.setParticipantNodes(ledgerAdminInfo.getParticipants()); | |||||
// 设置共识设置 | // 设置共识设置 | ||||
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerMetadata)); | |||||
ledgerBaseSettings.setConsensusSettings(initConsensusSettings(ledgerAdminInfo)); | |||||
// 设置参与方根Hash | // 设置参与方根Hash | ||||
ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | |||||
ledgerBaseSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | |||||
// 设置算法配置 | // 设置算法配置 | ||||
ledgerInitSettings.setCryptoSetting(ledgerMetadata.getSetting().getCryptoSetting()); | |||||
ledgerBaseSettings.setCryptoSetting(ledgerAdminInfo.getSettings().getCryptoSetting()); | |||||
// 设置种子 | // 设置种子 | ||||
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | |||||
ledgerBaseSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | |||||
// 设置共识协议 | // 设置共识协议 | ||||
ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider()); | |||||
ledgerBaseSettings.setConsensusProtocol(ledgerAdminInfo.getSettings().getConsensusProvider()); | |||||
return ledgerInitSettings; | |||||
return ledgerBaseSettings; | |||||
} | } | ||||
/** | /** | ||||
@@ -131,14 +130,14 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { | |||||
/** | /** | ||||
* 初始化共识配置 | * 初始化共识配置 | ||||
* | * | ||||
* @param ledgerMetadata | |||||
* @param ledgerAdminInfo | |||||
* 账本元数据 | * 账本元数据 | ||||
* @return | * @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); | ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | ||||
byte[] consensusSettingsBytes = ledgerMetadata.getSetting().getConsensusSetting().toBytes(); | |||||
byte[] consensusSettingsBytes = ledgerAdminInfo.getSettings().getConsensusSetting().toBytes(); | |||||
return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | ||||
} | } | ||||
} | } |
@@ -35,6 +35,18 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer { | |||||
JSONSerializeUtils.disableCircularReferenceDetect(); | JSONSerializeUtils.disableCircularReferenceDetect(); | ||||
JSONSerializeUtils.configStringSerializer(ByteArray.class); | JSONSerializeUtils.configStringSerializer(ByteArray.class); | ||||
DataContractRegistry.register(BftsmartNodeSettings.class); | DataContractRegistry.register(BftsmartNodeSettings.class); | ||||
// 注册角色/权限相关接口 | |||||
DataContractRegistry.register(RolesConfigureOperation.class); | |||||
DataContractRegistry.register(RolesConfigureOperation.RolePrivilegeEntry.class); | |||||
DataContractRegistry.register(UserAuthorizeOperation.class); | |||||
DataContractRegistry.register(UserAuthorizeOperation.UserRolesEntry.class); | |||||
DataContractRegistry.register(PrivilegeSet.class); | |||||
DataContractRegistry.register(RoleSet.class); | |||||
DataContractRegistry.register(SecurityInitSettings.class); | |||||
DataContractRegistry.register(RoleInitSettings.class); | |||||
DataContractRegistry.register(UserAuthInitSettings.class); | |||||
DataContractRegistry.register(LedgerMetadata_V2.class); | |||||
} | } | ||||
@@ -1,6 +1,7 @@ | |||||
package com.jd.blockchain.gateway.web; | package com.jd.blockchain.gateway.web; | ||||
import com.jd.blockchain.crypto.*; | import com.jd.blockchain.crypto.*; | ||||
import com.jd.blockchain.gateway.service.GatewayInterceptService; | |||||
import com.jd.blockchain.transaction.SignatureUtils; | import com.jd.blockchain.transaction.SignatureUtils; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.web.bind.annotation.RequestBody; | import org.springframework.web.bind.annotation.RequestBody; | ||||
@@ -29,9 +30,15 @@ public class TxProcessingController implements TransactionService { | |||||
@Autowired | @Autowired | ||||
private PeerService peerService; | private PeerService peerService; | ||||
@Autowired | |||||
private GatewayInterceptService interceptService; | |||||
@RequestMapping(path = "rpc/tx", method = RequestMethod.POST, consumes = BinaryMessageConverter.CONTENT_TYPE_VALUE, produces = BinaryMessageConverter.CONTENT_TYPE_VALUE) | @RequestMapping(path = "rpc/tx", method = RequestMethod.POST, consumes = BinaryMessageConverter.CONTENT_TYPE_VALUE, produces = BinaryMessageConverter.CONTENT_TYPE_VALUE) | ||||
@Override | @Override | ||||
public @ResponseBody TransactionResponse process(@RequestBody TransactionRequest txRequest) { | public @ResponseBody TransactionResponse process(@RequestBody TransactionRequest txRequest) { | ||||
// 拦截请求进行校验 | |||||
interceptService.intercept(txRequest); | |||||
// 检查交易请求的信息是否完整; | // 检查交易请求的信息是否完整; | ||||
HashDigest ledgerHash = txRequest.getTransactionContent().getLedgerHash(); | HashDigest ledgerHash = txRequest.getTransactionContent().getLedgerHash(); | ||||
if (ledgerHash == null) { | if (ledgerHash == null) { | ||||
@@ -13,12 +13,12 @@ | |||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | ||||
</console> | </console> | ||||
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用--> | <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用--> | ||||
<File name="log" fileName="../logs/test.log" append="false"> | |||||
<File name="log" fileName="${sys:gateway.log}/logs/gateway.temp.log" append="false"> | |||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> | ||||
</File> | </File> | ||||
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--> | <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--> | ||||
<RollingFile name="GatewayRollingInfo" fileName="../logs/gateway.out.info.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.info-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingInfo" fileName="${sys:gateway.log}/logs/gateway.info.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.info-%d{yyyy-MM-dd}-%i.log"> | |||||
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--> | ||||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
@@ -27,8 +27,8 @@ | |||||
<SizeBasedTriggeringPolicy size="100 MB"/> | <SizeBasedTriggeringPolicy size="100 MB"/> | ||||
</Policies> | </Policies> | ||||
</RollingFile> | </RollingFile> | ||||
<RollingFile name="GatewayRollingWarn" fileName="../logs/gateway.out.warn.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.warn-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingWarn" fileName="${sys:gateway.log}/logs/gateway.warn.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.out.warn-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
<Policies> | <Policies> | ||||
@@ -38,8 +38,8 @@ | |||||
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --> | <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --> | ||||
<DefaultRolloverStrategy max="20"/> | <DefaultRolloverStrategy max="20"/> | ||||
</RollingFile> | </RollingFile> | ||||
<RollingFile name="GatewayRollingError" fileName="../logs/gateway.out.error.log" | |||||
filePattern="../logs/$${date:yyyy-MM}/gateway.out.error-%d{yyyy-MM-dd}-%i.log"> | |||||
<RollingFile name="GatewayRollingError" fileName="${sys:gateway.log}/logs/gateway.error.log" | |||||
filePattern="${sys:gateway.log}/logs/$${date:yyyy-MM}/gateway.error-%d{yyyy-MM-dd}-%i.log"> | |||||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> | <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> | ||||
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/> | ||||
<Policies> | <Policies> | ||||
@@ -51,7 +51,7 @@ | |||||
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> | <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> | ||||
<loggers> | <loggers> | ||||
<!--过滤掉spring的一些DEBUG信息--> | <!--过滤掉spring的一些DEBUG信息--> | ||||
<logger name="org.springframework" level="INFO"></logger> | |||||
<logger name="org.springframework" level="INFO"/> | |||||
<root level="all"> | <root level="all"> | ||||
<appender-ref ref="Console"/> | <appender-ref ref="Console"/> | ||||
<appender-ref ref="GatewayRollingInfo"/> | <appender-ref ref="GatewayRollingInfo"/> | ||||
@@ -40,6 +40,11 @@ | |||||
<artifactId>contract-framework</artifactId> | <artifactId>contract-framework</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>consensus-framework</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
<artifactId>contract-jvm</artifactId> | <artifactId>contract-jvm</artifactId> | ||||
@@ -1,26 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public interface AccountPrivilege { | |||||
/** | |||||
* 数据“读”的操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte getReadingOpCode(); | |||||
/** | |||||
* “写”的操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte getWrittingOpCode(); | |||||
/** | |||||
* 其它的扩展操作码; | |||||
* | |||||
* @return | |||||
*/ | |||||
byte[] getExtOpCodes(); | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public interface AccountQuery<T> extends MerkleProvable { | |||||
AccountHeader[] getHeaders(int fromIndex, int count); | |||||
/** | |||||
* 返回总数; | |||||
* | |||||
* @return | |||||
*/ | |||||
long getTotal(); | |||||
boolean contains(Bytes address); | |||||
/** | |||||
* 返回账户实例; | |||||
* | |||||
* @param address Base58 格式的账户地址; | |||||
* @return 账户实例,如果不存在则返回 null; | |||||
*/ | |||||
T getAccount(String address); | |||||
T getAccount(Bytes address); | |||||
T getAccount(Bytes address, long version); | |||||
} |
@@ -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(); | |||||
// } | |||||
// | |||||
//} |
@@ -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(); | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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,10 +2,10 @@ package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | 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.BytesData; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.ContractInfo; | import com.jd.blockchain.ledger.ContractInfo; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class ContractAccount implements ContractInfo { | public class ContractAccount implements ContractInfo { | ||||
@@ -14,9 +14,9 @@ public class ContractAccount implements ContractInfo { | |||||
private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); | private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); | ||||
private BaseAccount accBase; | |||||
private MerkleAccount accBase; | |||||
public ContractAccount(BaseAccount accBase) { | |||||
public ContractAccount(MerkleAccount accBase) { | |||||
this.accBase = accBase; | this.accBase = accBase; | ||||
} | } | ||||
@@ -57,7 +57,7 @@ public class ContractAccount implements ContractInfo { | |||||
} | } | ||||
public long getChaincodeVersion() { | public long getChaincodeVersion() { | ||||
return accBase.getKeyVersion(CHAIN_CODE_KEY); | |||||
return accBase.getVersion(CHAIN_CODE_KEY); | |||||
} | } | ||||
public long setProperty(Bytes key, String value, long version) { | public long setProperty(Bytes key, String value, long version) { | ||||
@@ -0,0 +1,5 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public interface ContractAccountQuery extends AccountQuery<ContractAccount> { | |||||
} |
@@ -5,34 +5,40 @@ import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | 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.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||||
private AccountSet accountSet; | |||||
private MerkleAccountSet accountSet; | |||||
public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | ||||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | ||||
accountSet = new AccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||||
accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||||
} | } | ||||
public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | ||||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | ||||
AccountAccessPolicy accessPolicy) { | AccountAccessPolicy accessPolicy) { | ||||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||||
} | } | ||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||||
return accountSet.getAccounts(fromIndex,count); | |||||
@Override | |||||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||||
return accountSet.getHeaders(fromIndex, count); | |||||
} | } | ||||
public boolean isReadonly() { | public boolean isReadonly() { | ||||
return accountSet.isReadonly(); | return accountSet.isReadonly(); | ||||
} | } | ||||
void setReadonly() { | |||||
accountSet.setReadonly(); | |||||
} | |||||
@Override | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return accountSet.getRootHash(); | return accountSet.getRootHash(); | ||||
@@ -43,8 +49,9 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
* | * | ||||
* @return | * @return | ||||
*/ | */ | ||||
public long getTotalCount() { | |||||
return accountSet.getTotalCount(); | |||||
@Override | |||||
public long getTotal() { | |||||
return accountSet.getTotal(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -52,36 +59,40 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
return accountSet.getProof(address); | return accountSet.getProof(address); | ||||
} | } | ||||
@Override | |||||
public boolean contains(Bytes address) { | public boolean contains(Bytes address) { | ||||
return accountSet.contains(address); | return accountSet.contains(address); | ||||
} | } | ||||
public ContractAccount getContract(Bytes address) { | |||||
BaseAccount accBase = accountSet.getAccount(address); | |||||
@Override | |||||
public ContractAccount getAccount(Bytes address) { | |||||
MerkleAccount accBase = accountSet.getAccount(address); | |||||
return new ContractAccount(accBase); | return new ContractAccount(accBase); | ||||
} | } | ||||
public ContractAccount getContract(Bytes address, long version) { | |||||
BaseAccount accBase = accountSet.getAccount(address, version); | |||||
@Override | |||||
public ContractAccount getAccount(String address) { | |||||
return getAccount(Bytes.fromBase58(address)); | |||||
} | |||||
@Override | |||||
public ContractAccount getAccount(Bytes address, long version) { | |||||
MerkleAccount accBase = accountSet.getAccount(address, version); | |||||
return new ContractAccount(accBase); | return new ContractAccount(accBase); | ||||
} | } | ||||
/** | /** | ||||
* 部署一项新的合约链码; | * 部署一项新的合约链码; | ||||
* | * | ||||
* @param address | |||||
* 合约账户地址; | |||||
* @param pubKey | |||||
* 合约账户公钥; | |||||
* @param addressSignature | |||||
* 地址签名;合约账户的私钥对地址的签名; | |||||
* @param chaincode | |||||
* 链码内容; | |||||
* @param address 合约账户地址; | |||||
* @param pubKey 合约账户公钥; | |||||
* @param addressSignature 地址签名;合约账户的私钥对地址的签名; | |||||
* @param chaincode 链码内容; | |||||
* @return 合约账户; | * @return 合约账户; | ||||
*/ | */ | ||||
public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { | public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { | ||||
// TODO: 校验和记录合约地址签名; | // TODO: 校验和记录合约地址签名; | ||||
BaseAccount accBase = accountSet.register(address, pubKey); | |||||
MerkleAccount accBase = accountSet.register(address, pubKey); | |||||
ContractAccount contractAcc = new ContractAccount(accBase); | ContractAccount contractAcc = new ContractAccount(accBase); | ||||
contractAcc.setChaincode(chaincode, -1); | contractAcc.setChaincode(chaincode, -1); | ||||
return contractAcc; | return contractAcc; | ||||
@@ -90,16 +101,13 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||||
/** | /** | ||||
* 更新指定账户的链码; | * 更新指定账户的链码; | ||||
* | * | ||||
* @param address | |||||
* 合约账户地址; | |||||
* @param chaincode | |||||
* 链码内容; | |||||
* @param version | |||||
* 链码版本; | |||||
* @param address 合约账户地址; | |||||
* @param chaincode 链码内容; | |||||
* @param version 链码版本; | |||||
* @return 返回链码的新版本号; | * @return 返回链码的新版本号; | ||||
*/ | */ | ||||
public long update(Bytes address, byte[] chaincode, long version) { | public long update(Bytes address, byte[] chaincode, long version) { | ||||
BaseAccount accBase = accountSet.getAccount(address); | |||||
MerkleAccount accBase = accountSet.getAccount(address); | |||||
ContractAccount contractAcc = new ContractAccount(accBase); | ContractAccount contractAcc = new ContractAccount(accBase); | ||||
return contractAcc.setChaincode(chaincode, version); | return contractAcc.setChaincode(chaincode, version); | ||||
} | } | ||||
@@ -82,7 +82,7 @@ public class CryptoConfig implements CryptoSetting { | |||||
public void setHashAlgorithm(short hashAlgorithm) { | public void setHashAlgorithm(short hashAlgorithm) { | ||||
if (codeAlgorithms == null || !codeAlgorithms.containsKey(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; | this.hashAlgorithm = hashAlgorithm; | ||||
} | } | ||||
@@ -1,21 +1,21 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesData; | import com.jd.blockchain.ledger.BytesData; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
import com.jd.blockchain.ledger.KVDataObject; | import com.jd.blockchain.ledger.KVDataObject; | ||||
import com.jd.blockchain.ledger.MerkleProof; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class DataAccount implements AccountHeader, MerkleProvable { | public class DataAccount implements AccountHeader, MerkleProvable { | ||||
private BaseAccount baseAccount; | |||||
private MerkleAccount baseAccount; | |||||
public DataAccount(BaseAccount accBase) { | |||||
public DataAccount(MerkleAccount accBase) { | |||||
this.baseAccount = accBase; | this.baseAccount = accBase; | ||||
} | } | ||||
@@ -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) { | public long setBytes(Bytes key, BytesValue value, long version) { | ||||
return baseAccount.setBytes(key, value, 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) { | public long setBytes(Bytes key, String value, long version) { | ||||
BytesValue bytesValue = BytesData.fromText(value); | BytesValue bytesValue = BytesData.fromText(value); | ||||
return baseAccount.setBytes(key, bytesValue, version); | 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) { | public long setBytes(Bytes key, byte[] value, long version) { | ||||
BytesValue bytesValue = BytesData.fromBytes(value); | BytesValue bytesValue = BytesData.fromBytes(value); | ||||
return baseAccount.setBytes(key, bytesValue, version); | return baseAccount.setBytes(key, bytesValue, version); | ||||
@@ -66,7 +135,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
* @return | * @return | ||||
*/ | */ | ||||
public long getDataVersion(String key) { | public long getDataVersion(String key) { | ||||
return baseAccount.getKeyVersion(Bytes.fromString(key)); | |||||
return baseAccount.getVersion(Bytes.fromString(key)); | |||||
} | } | ||||
/** | /** | ||||
@@ -77,7 +146,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
* @return | * @return | ||||
*/ | */ | ||||
public long getDataVersion(Bytes key) { | public long getDataVersion(Bytes key) { | ||||
return baseAccount.getKeyVersion(key); | |||||
return baseAccount.getVersion(key); | |||||
} | } | ||||
/** | /** | ||||
@@ -121,6 +190,29 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
public BytesValue getBytes(Bytes key, long version) { | public BytesValue getBytes(Bytes key, long version) { | ||||
return baseAccount.getBytes(key, 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; | * return the specified index's KVDataEntry; | ||||
@@ -131,7 +223,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
*/ | */ | ||||
public KVDataEntry[] getDataEntries(int fromIndex, int count) { | public KVDataEntry[] getDataEntries(int fromIndex, int count) { | ||||
if (getDataEntriesTotalCount() == 0 || count == 0) { | |||||
if (count == 0 || getDataEntriesTotalCount() == 0) { | |||||
return null; | return null; | ||||
} | } | ||||
@@ -0,0 +1,5 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public interface DataAccountQuery extends AccountQuery<DataAccount> { | |||||
} |
@@ -5,41 +5,53 @@ import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | 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.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
public class DataAccountSet implements MerkleProvable, Transactional { | |||||
public class DataAccountSet implements Transactional, DataAccountQuery { | |||||
private AccountSet accountSet; | |||||
private MerkleAccountSet accountSet; | |||||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | ||||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | ||||
accountSet = new AccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||||
accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||||
} | } | ||||
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | ||||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | ||||
AccountAccessPolicy accessPolicy) { | AccountAccessPolicy accessPolicy) { | ||||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||||
} | } | ||||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||||
return accountSet.getAccounts(fromIndex, count); | |||||
@Override | |||||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||||
return accountSet.getHeaders(fromIndex, count); | |||||
} | } | ||||
public boolean isReadonly() { | public boolean isReadonly() { | ||||
return accountSet.isReadonly(); | return accountSet.isReadonly(); | ||||
} | } | ||||
void setReadonly() { | |||||
accountSet.setReadonly(); | |||||
} | |||||
@Override | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return accountSet.getRootHash(); | return accountSet.getRootHash(); | ||||
} | } | ||||
public long getTotalCount() { | |||||
return accountSet.getTotalCount(); | |||||
@Override | |||||
public long getTotal() { | |||||
return accountSet.getTotal(); | |||||
} | |||||
@Override | |||||
public boolean contains(Bytes address) { | |||||
return accountSet.contains(address); | |||||
} | } | ||||
/** | /** | ||||
@@ -52,10 +64,15 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||||
public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { | public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { | ||||
// TODO: 未实现对地址签名的校验和记录; | // TODO: 未实现对地址签名的校验和记录; | ||||
BaseAccount accBase = accountSet.register(address, pubKey); | |||||
MerkleAccount accBase = accountSet.register(address, pubKey); | |||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
} | } | ||||
@Override | |||||
public DataAccount getAccount(String address) { | |||||
return getAccount(Bytes.fromBase58(address)); | |||||
} | |||||
/** | /** | ||||
* 返回数据账户; <br> | * 返回数据账户; <br> | ||||
* 如果不存在,则返回 null; | * 如果不存在,则返回 null; | ||||
@@ -63,16 +80,18 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||||
* @param address | * @param address | ||||
* @return | * @return | ||||
*/ | */ | ||||
public DataAccount getDataAccount(Bytes address) { | |||||
BaseAccount accBase = accountSet.getAccount(address); | |||||
@Override | |||||
public DataAccount getAccount(Bytes address) { | |||||
MerkleAccount accBase = accountSet.getAccount(address); | |||||
if (accBase == null) { | if (accBase == null) { | ||||
return null; | return null; | ||||
} | } | ||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
} | } | ||||
public DataAccount getDataAccount(Bytes address, long version) { | |||||
BaseAccount accBase = accountSet.getAccount(address, version); | |||||
@Override | |||||
public DataAccount getAccount(Bytes address, long version) { | |||||
MerkleAccount accBase = accountSet.getAccount(address, version); | |||||
return new DataAccount(accBase); | return new DataAccount(accBase); | ||||
} | } | ||||
@@ -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; | |||||
} | |||||
} |
@@ -0,0 +1,52 @@ | |||||
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 class EmptyAccountSet<T> implements AccountQuery<T> { | |||||
private static final AccountHeader[] EMPTY = {}; | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes key) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||||
return EMPTY; | |||||
} | |||||
@Override | |||||
public long getTotal() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public boolean contains(Bytes address) { | |||||
return false; | |||||
} | |||||
@Override | |||||
public T getAccount(String address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public T getAccount(Bytes address) { | |||||
return null; | |||||
} | |||||
@Override | |||||
public T getAccount(Bytes address, long version) { | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,105 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.LedgerAdminSettings; | |||||
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 LedgerAdminSettings 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 extends EmptyAccountSet<UserAccount> implements UserAccountQuery{ | |||||
} | |||||
private static class EmptyDataAccountSet extends EmptyAccountSet<DataAccount> implements DataAccountQuery{ | |||||
} | |||||
private static class EmptyContractAccountSet extends EmptyAccountSet<ContractAccount> implements ContractAccountQuery{ | |||||
} | |||||
} |
@@ -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 { | |||||
} | |||||
} | |||||
} |
@@ -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(); | |||||
} | |||||
} |