com.jd.blockchain.ledger.LedgerInitProperties Maven / Gradle / Ivy
package com.jd.blockchain.ledger;
import com.jd.blockchain.ca.CertificateRole;
import com.jd.blockchain.ca.CertificateUtils;
import com.jd.blockchain.consts.Global;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.KeyGenUtils;
import com.jd.blockchain.crypto.PubKey;
import utils.Bytes;
import utils.PropertiesUtils;
import utils.StringUtils;
import utils.codec.HexUtils;
import utils.io.FileUtils;
import utils.net.NetworkAddress;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class LedgerInitProperties implements Serializable {
private static final long serialVersionUID = 6261483113521649870L;
// 账本种子;
public static final String LEDGER_SEED = "ledger.seed";
// 证书模式,默认 false
public static final String IDENTITY_MODE = "identity-mode";
// 根证书路径,CA_MODE 为 true 时,此选项不能为空,支持多个,半角逗号相隔
public static final String CA_PATH = "root-ca-path";
// 账本名称
public static final String LEDGER_NAME = "ledger.name";
// 声明的账本建立时间;
public static final String CREATED_TIME = "created-time";
// 创建时间的格式;
public static final String CREATED_TIME_FORMAT = Global.DEFAULT_TIME_FORMAT;
// 合约运行超时配置
public static final String CONTRACT_TIMEOUT = "contract.timeout";
// 合约运行超时默认值:1分钟
public static final int DEFAULt_CONTRACT_TIMEOUT = 60000;
// 角色清单;
public static final String ROLES = "security.roles";
// 角色的账本权限;用角色名称替代占位符;
public static final String ROLE_LEDGER_PRIVILEGES_PATTERN = "security.role.%s.ledger-privileges";
// 角色的交易权限;用角色名称替代占位符;
public static final String ROLE_TX_PRIVILEGES_PATTERN = "security.role.%s.tx-privileges";
// 共识参与方的个数,后续以 part.id 分别标识每一个参与方的配置;
public static final String PART_COUNT = "cons_parti.count";
// 共识参与方的名称的模式;
public static final String PART_ID_PATTERN = "cons_parti.%s";
// 参与方的名称;
public static final String PART_NAME = "name";
// 参与方的公钥文件路径;
public static final String PART_PUBKEY_PATH = "pubkey-path";
// 参与方的公钥文件路径;
public static final String PART_PUBKEY = "pubkey";
// 参与方证书文件路径
public static final String PART_CA_PATH = "ca-path";
// 参与方的角色清单;
public static final String PART_ROLES = "roles";
// 参与方的角色权限策略;
public static final String PART_ROLES_POLICY = "roles-policy";
// 共识参与方的账本初始服务的主机;
public static final String PART_INITIALIZER_HOST = "initializer.host";
// 共识参与方的账本初始服务的端口;
public static final String PART_INITIALIZER_PORT = "initializer.port";
// 共识参与方的账本初始服务是否开启安全连接;
public static final String PART_INITIALIZER_SECURE = "initializer.secure";
// 共识参与方的状态;
public static final String PART_INITIALIZER_STATE = "initializer.state";
// 共识服务的参数配置;必须;
public static final String CONSENSUS_CONFIG = "consensus.conf";
// 共识服务提供者;必须;
public static final String CONSENSUS_SERVICE_PROVIDER = "consensus.service-provider";
// 密码服务提供者列表,以英文逗点“,”分隔;必须;
public static final String CRYPTO_SERVICE_PROVIDERS = "crypto.service-providers";
// 从存储中加载账本数据时,是否校验哈希;可选;
public static final String CRYPTO_VRIFY_HASH = "crypto.verify-hash";
// 哈希算法;
public static final String CRYPTO_HASH_ALGORITHM = "crypto.hash-algorithm";
public static final String LEDGER_DATA_STRUCTURE = "ledger.data.structure";
public static final String CRYPTO_SERVICE_PROVIDERS_SPLITTER = ",";
private byte[] ledgerSeed;
private IdentityMode identityMode;
private String[] ledgerCertificates;
private String ledgerName;
private RoleInitData[] roles;
private List consensusParticipants = new ArrayList<>();
private GenesisUser[] genesisUsers;
private String consensusProvider;
private Properties consensusConfig;
private CryptoProperties cryptoProperties = new CryptoProperties();
private long createdTime;
private LedgerDataStructure ledgerDataStructure;
private long contractTimeout;
public byte[] getLedgerSeed() {
return ledgerSeed.clone();
}
public IdentityMode getIdentityMode() {
return identityMode;
}
public String[] getLedgerCertificates() {
return ledgerCertificates;
}
public GenesisUser[] getGenesisUsers() {
return genesisUsers;
}
public void setGenesisUsers(GenesisUser[] genesisUsers) {
this.genesisUsers = genesisUsers;
}
public String getLedgerName() {
return ledgerName;
}
public long getCreatedTime() {
return createdTime;
}
public LedgerDataStructure getLedgerDataStructure() {
return ledgerDataStructure;
}
public long getContractTimeout() {
return contractTimeout;
}
public Properties getConsensusConfig() {
return consensusConfig;
}
public String getConsensusProvider() {
return consensusProvider;
}
public int getConsensusParticipantCount() {
return consensusParticipants.size();
}
public List getConsensusParticipants() {
return consensusParticipants;
}
public ParticipantNode[] getConsensusParticipantNodes() {
if (consensusParticipants.isEmpty()) {
return null;
}
ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipants.size()];
return consensusParticipants.toArray(participantNodes);
}
public CryptoProperties getCryptoProperties() {
return cryptoProperties;
}
public void setCryptoProperties(CryptoProperties cryptoProperties) {
if (cryptoProperties == null) {
cryptoProperties = new CryptoProperties();
}
this.cryptoProperties = cryptoProperties;
}
/**
* 返回参与者;
*
* @param id 从 1 开始; 小于等于 {@link #getConsensusParticipantCount()};
* @return
*/
public ParticipantProperties getConsensusParticipant(int id) {
for (ParticipantProperties p : consensusParticipants) {
if (p.getId() == id) {
return p;
}
}
return null;
}
/**
* 私有的构造器;
*
* @param ledgerSeed
*/
private LedgerInitProperties(byte[] ledgerSeed) {
this.ledgerSeed = ledgerSeed;
}
public void addConsensusParticipant(ParticipantProperties participant) {
consensusParticipants.add(participant);
}
private static String getKeyOfParticipant(int partId, String partPropKey) {
String partAddrStr = String.format(PART_ID_PATTERN, partId);
return String.format("%s.%s", partAddrStr, partPropKey);
}
public static LedgerInitProperties createDefault(byte[] ledgerSeed, String ledgerName, Date createdTime, LedgerDataStructure ledgerDataStructure,
Properties consensusConfig, CryptoProperties cryptoProperties) {
LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed);
initProps.ledgerName = ledgerName;
initProps.createdTime = createdTime.getTime();
initProps.ledgerDataStructure = ledgerDataStructure;
initProps.consensusProvider = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider";
initProps.consensusConfig = consensusConfig;
initProps.cryptoProperties = cryptoProperties.clone();
return initProps;
}
public static LedgerInitProperties resolve(String initSettingFile) {
Properties props = FileUtils.readProperties(initSettingFile, "UTF-8");
File realFile = new File(initSettingFile);
return resolve(realFile.getParentFile().getPath(), props);
}
public static LedgerInitProperties resolve(InputStream in) {
Properties props = FileUtils.readProperties(in, "UTF-8");
return resolve(props);
}
public static LedgerInitProperties resolve(Properties props) {
return resolve(null, props);
}
/**
* 从属性表解析账本初始化参数;
*
* @param baseDirectory 基础路径;属性中涉及文件位置的相对路径以此参数指定的目录为父目录;
* @param props 要解析的属性表;
* @return
*/
public static LedgerInitProperties resolve(String baseDirectory, Properties props) {
String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", "");
byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed);
LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed);
// 证书配置
String identityMode = PropertiesUtils.getOptionalProperty(props, IDENTITY_MODE, IdentityMode.KEYPAIR.name());
initProps.identityMode = IdentityMode.valueOf(identityMode);
X509Certificate[] ledgerCerts = null;
if (initProps.identityMode == IdentityMode.CA) {
// 根证书
String[] ledgerCAPaths = PropertiesUtils.getRequiredProperty(props, CA_PATH).split(",");
if (ledgerCAPaths.length == 0) {
throw new LedgerInitException("root-ca-path is empty");
}
ledgerCerts = new X509Certificate[ledgerCAPaths.length];
String[] ledgersCAs = new String[ledgerCAPaths.length];
for (int i = 0; i < ledgerCAPaths.length; i++) {
ledgersCAs[i] = FileUtils.readText(ledgerCAPaths[i]);
ledgerCerts[i] = CertificateUtils.parseCertificate(ledgersCAs[i]);
// 时间有效性校验
CertificateUtils.checkValidity(ledgerCerts[i]);
// 证书类型校验
CertificateUtils.checkCACertificate(ledgerCerts[i]);
}
initProps.ledgerCertificates = ledgersCAs;
}
// 解析账本信息;
// 账本名称
String ledgerName = PropertiesUtils.getRequiredProperty(props, LEDGER_NAME);
initProps.ledgerName = ledgerName;
// 创建时间;
String strCreatedTime = PropertiesUtils.getRequiredProperty(props, CREATED_TIME);
try {
initProps.createdTime = new SimpleDateFormat(CREATED_TIME_FORMAT).parse(strCreatedTime).getTime();
} catch (ParseException ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
// 合约运行时参数
initProps.contractTimeout = PropertiesUtils.getIntOptional(props, CONTRACT_TIMEOUT, DEFAULt_CONTRACT_TIMEOUT);
String dataStructure = PropertiesUtils.getOptionalProperty(props, LEDGER_DATA_STRUCTURE, LedgerDataStructure.MERKLE_TREE.name());
initProps.ledgerDataStructure = LedgerDataStructure.valueOf(dataStructure);
// 解析角色清单;
String strRoleNames = PropertiesUtils.getOptionalProperty(props, ROLES);
String[] roles = StringUtils.splitToArray(strRoleNames, ",");
Map rolesInitSettingMap = new TreeMap();
// 解析角色权限表;
for (String role : roles) {
String ledgerPrivilegeKey = getKeyOfRoleLedgerPrivilege(role);
String strLedgerPermissions = PropertiesUtils.getOptionalProperty(props, ledgerPrivilegeKey);
LedgerPermission[] ledgerPermissions = resolveLedgerPermissions(strLedgerPermissions);
String txPrivilegeKey = getKeyOfRoleTxPrivilege(role);
String strTxPermissions = PropertiesUtils.getOptionalProperty(props, txPrivilegeKey);
TransactionPermission[] txPermissions = resolveTransactionPermissions(strTxPermissions);
if (ledgerPermissions.length > 0 || txPermissions.length > 0) {
RoleInitData rolesSettings = new RoleInitData(role, ledgerPermissions, txPermissions);
rolesInitSettingMap.put(role, rolesSettings);
}
}
RoleInitData[] rolesInitDatas = rolesInitSettingMap.values()
.toArray(new RoleInitData[rolesInitSettingMap.size()]);
initProps.setRoles(rolesInitDatas);
// 解析共识相关的属性;
initProps.consensusProvider = PropertiesUtils.getRequiredProperty(props, CONSENSUS_SERVICE_PROVIDER);
ConsensusTypeEnum consensusType = ConsensusTypeEnum.of(initProps.consensusProvider);
if (consensusType.equals(ConsensusTypeEnum.UNKNOWN)) {
throw new IllegalArgumentException(String.format("Property[%s] is unsupported!", CONSENSUS_SERVICE_PROVIDER));
}
String consensusConfigFilePath = PropertiesUtils.getRequiredProperty(props, CONSENSUS_CONFIG);
try {
initProps.consensusConfig = FileUtils.readPropertiesResouce(consensusConfigFilePath, baseDirectory);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(
String.format("Consensus config file[%s] doesn't exist! ", consensusConfigFilePath), e);
}
// 解析密码提供者列表;
String cryptoProviderNames = PropertiesUtils.getProperty(props, CRYPTO_SERVICE_PROVIDERS, true);
String[] cryptoProviders = cryptoProviderNames.split(CRYPTO_SERVICE_PROVIDERS_SPLITTER);
for (int i = 0; i < cryptoProviders.length; i++) {
cryptoProviders[i] = cryptoProviders[i].trim();
}
initProps.cryptoProperties.setProviders(cryptoProviders);
// 哈希校验选项;
boolean verifyHash = PropertiesUtils.getBooleanOptional(props, CRYPTO_VRIFY_HASH, false);
initProps.cryptoProperties.setVerifyHash(verifyHash);
// 哈希算法;
String hashAlgorithm = PropertiesUtils.getOptionalProperty(props, CRYPTO_HASH_ALGORITHM);
initProps.cryptoProperties.setHashAlgorithm(hashAlgorithm);
// 解析参与方节点列表;
int partCount = getInt(PropertiesUtils.getRequiredProperty(props, PART_COUNT));
if (partCount < 0) {
throw new IllegalArgumentException(String.format("Property[%s] is negative!", PART_COUNT));
}
GenesisUser[] genesisUsers = new GenesisUserConfig[partCount];
int consensusNodeCount = 0;
for (int i = 0; i < partCount; i++) {
ParticipantProperties parti = new ParticipantProperties();
parti.setId(i);
String nameKey = getKeyOfParticipant(i, PART_NAME);
parti.setName(PropertiesUtils.getRequiredProperty(props, nameKey));
String pubkeyPathKey = getKeyOfParticipant(i, PART_PUBKEY_PATH);
String pubkeyKey = getKeyOfParticipant(i, PART_PUBKEY);
String partCAPathKey = getKeyOfParticipant(i, PART_CA_PATH);
PubKey pubKey;
String ca = null;
boolean isGw = false;
if (initProps.identityMode == IdentityMode.CA) {
ca = FileUtils.readText(PropertiesUtils.getRequiredProperty(props, partCAPathKey));
X509Certificate cert = CertificateUtils.parseCertificate(ca);
CertificateUtils.checkValidity(cert);
// CA模式下,初始化的节点证书必须是 PEER 和 GW 角色类型
CertificateUtils.checkCertificateRolesAny(cert, CertificateRole.PEER, CertificateRole.GW);
isGw = CertificateUtils.checkCertificateRolesAnyNoException(cert, CertificateRole.GW);
CertificateUtils.verifyAny(cert, ledgerCerts);
pubKey = CertificateUtils.resolvePubKey(cert);
} else {
String base58PubKey = PropertiesUtils.getProperty(props, pubkeyKey, false);
String pubkeyPath = PropertiesUtils.getProperty(props, pubkeyPathKey, false);
String pCA = PropertiesUtils.getProperty(props, partCAPathKey, false);
if (base58PubKey != null) {
pubKey = KeyGenUtils.decodePubKey(base58PubKey);
} else if (pubkeyPath != null) {
pubKey = KeyGenUtils.readPubKey(pubkeyPath);
} else if (pCA != null) {
pubKey = CertificateUtils.resolvePubKey(CertificateUtils.parseCertificate(FileUtils.readText(pCA)));
} else {
throw new IllegalArgumentException(
String.format("Property[%s] and property[%s] are all empty!", pubkeyKey, pubkeyPathKey));
}
}
parti.setPubKey(pubKey);
// 解析参与方的角色权限配置;
String partiRolesKey = getKeyOfParticipant(i, PART_ROLES);
String strPartiRoles = PropertiesUtils.getOptionalProperty(props, partiRolesKey);
String[] partiRoles = StringUtils.splitToArray(strPartiRoles, ",");
String partiRolePolicyKey = getKeyOfParticipant(i, PART_ROLES_POLICY);
String strPartiPolicy = PropertiesUtils.getOptionalProperty(props, partiRolePolicyKey);
RolesPolicy policy = strPartiPolicy == null ? RolesPolicy.UNION
: RolesPolicy.valueOf(strPartiPolicy.trim());
policy = policy == null ? RolesPolicy.UNION : policy;
if (!isGw) {
consensusNodeCount++;
// 解析参与方的网络配置参数;
String initializerHostKey = getKeyOfParticipant(i, PART_INITIALIZER_HOST);
String initializerHost = PropertiesUtils.getRequiredProperty(props, initializerHostKey);
String initializerPortKey = getKeyOfParticipant(i, PART_INITIALIZER_PORT);
int initializerPort = getInt(PropertiesUtils.getRequiredProperty(props, initializerPortKey));
String initializerSecureKey = getKeyOfParticipant(i, PART_INITIALIZER_SECURE);
boolean initializerSecure = Boolean
.parseBoolean(PropertiesUtils.getRequiredProperty(props, initializerSecureKey));
NetworkAddress initializerAddress = new NetworkAddress(initializerHost, initializerPort, initializerSecure);
parti.setInitializerAddress(initializerAddress);
} else {
parti.setInitializerAddress(new NetworkAddress("127.0.0.1", 8080));
}
parti.setParticipantNodeState(isGw ? ParticipantNodeState.READY : ParticipantNodeState.CONSENSUS);
initProps.addConsensusParticipant(parti);
genesisUsers[i] = new GenesisUserConfig(pubKey, ca, partiRoles, policy);
}
if (partCount < consensusType.getMinimalNodeSize()) {
throw new IllegalArgumentException(String.format("Consensus peer nodes size [%s] is less than [%s]!", consensusNodeCount, consensusType.getMinimalNodeSize()));
}
initProps.setGenesisUsers(genesisUsers);
return initProps;
}
private static TransactionPermission[] resolveTransactionPermissions(String strTxPermissions) {
String[] strPermissions = StringUtils.splitToArray(strTxPermissions, ",");
List permissions = new ArrayList();
if (strPermissions != null) {
for (String pm : strPermissions) {
TransactionPermission permission = TransactionPermission.valueOf(pm);
if (permission != null) {
permissions.add(permission);
}
}
}
return permissions.toArray(new TransactionPermission[permissions.size()]);
}
private static LedgerPermission[] resolveLedgerPermissions(String strLedgerPermissions) {
String[] strPermissions = StringUtils.splitToArray(strLedgerPermissions, ",");
List permissions = new ArrayList();
if (strPermissions != null) {
for (String pm : strPermissions) {
LedgerPermission permission = LedgerPermission.valueOf(pm);
if (permission != null) {
permissions.add(permission);
}
}
}
return permissions.toArray(new LedgerPermission[permissions.size()]);
}
private static String getKeyOfRoleLedgerPrivilege(String role) {
return String.format(ROLE_LEDGER_PRIVILEGES_PATTERN, role);
}
private static String getKeyOfRoleTxPrivilege(String role) {
return String.format(ROLE_TX_PRIVILEGES_PATTERN, role);
}
private static int getInt(String strInt) {
return Integer.parseInt(strInt.trim());
}
public RoleInitData[] getRoles() {
return roles;
}
public void setRoles(RoleInitData[] roles) {
this.roles = roles;
}
public static class CryptoProperties implements Serializable {
private static final long serialVersionUID = -2464539697473908124L;
private String[] providers;
private boolean verifyHash;
private String hashAlgorithm;
public String[] getProviders() {
return providers;
}
public void setProviders(String[] providers) {
this.providers = providers;
}
public boolean isVerifyHash() {
return verifyHash;
}
public void setVerifyHash(boolean verifyHash) {
this.verifyHash = verifyHash;
}
public String getHashAlgorithm() {
return hashAlgorithm;
}
public void setHashAlgorithm(String hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm;
}
@Override
protected CryptoProperties clone() {
CryptoProperties cryptoProperties = new CryptoProperties();
cryptoProperties.hashAlgorithm = hashAlgorithm;
cryptoProperties.providers = providers.clone();
cryptoProperties.verifyHash = verifyHash;
return cryptoProperties;
}
}
/**
* 参与方配置信息;
*
* @author huanghaiquan
*/
public static class ParticipantProperties implements ParticipantNode, Serializable {
private static final long serialVersionUID = 7038013516766733725L;
private int id;
private Bytes address;
private String name;
private PubKey pubKey;
private ParticipantNodeState participantNodeState;
private NetworkAddress initializerAddress;
@Override
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public Bytes getAddress() {
return address;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ParticipantNodeState getParticipantNodeState() {
return participantNodeState;
}
public void setParticipantNodeState(ParticipantNodeState participantNodeState) {
this.participantNodeState = participantNodeState;
}
public NetworkAddress getInitializerAddress() {
return initializerAddress;
}
public void setInitializerAddress(NetworkAddress initializerAddress) {
this.initializerAddress = initializerAddress;
}
@Override
public PubKey getPubKey() {
return pubKey;
}
public void setPubKey(PubKey pubKey) {
this.pubKey = pubKey;
this.address = AddressEncoding.generateAddress(pubKey);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy