@@ -18,6 +18,7 @@ import com.jd.blockchain.ledger.core.OperationHandleContext; | |||||
import com.jd.blockchain.ledger.core.SecurityContext; | import com.jd.blockchain.ledger.core.SecurityContext; | ||||
import com.jd.blockchain.ledger.core.SecurityPolicy; | import com.jd.blockchain.ledger.core.SecurityPolicy; | ||||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | import com.jd.blockchain.ledger.core.TransactionRequestExtension; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
public class UserAuthorizeOperationHandle extends AbstractLedgerOperationHandle<UserAuthorizeOperation> { | public class UserAuthorizeOperationHandle extends AbstractLedgerOperationHandle<UserAuthorizeOperation> { | ||||
public UserAuthorizeOperationHandle() { | public UserAuthorizeOperationHandle() { | ||||
@@ -49,21 +50,25 @@ public class UserAuthorizeOperationHandle extends AbstractLedgerOperationHandle< | |||||
} | } | ||||
} | } | ||||
} | } | ||||
UserRoles ur = urSettings.getUserRoles(urcfg.getUserAddress()); | |||||
if (ur == null) { | |||||
RolesPolicy policy = urcfg.getPolicy(); | |||||
if (policy == null) { | |||||
policy = RolesPolicy.UNION; | |||||
} | |||||
urSettings.addUserRoles(urcfg.getUserAddress(), policy, validRoles); | |||||
} else { | |||||
ur.addRoles(validRoles); | |||||
ur.removeRoles(urcfg.getUnauthorizedRoles()); | |||||
for (Bytes address : urcfg.getUserAddresses()) { | |||||
UserRoles ur = urSettings.getUserRoles(address); | |||||
if (ur == null) { | |||||
// 这是新的授权; | |||||
RolesPolicy policy = urcfg.getPolicy(); | |||||
if (policy == null) { | |||||
policy = RolesPolicy.UNION; | |||||
} | |||||
urSettings.addUserRoles(address, policy, validRoles); | |||||
} else { | |||||
// 更改之前的授权; | |||||
ur.addRoles(validRoles); | |||||
ur.removeRoles(urcfg.getUnauthorizedRoles()); | |||||
// 如果请求中设置了策略,才进行更新; | |||||
RolesPolicy policy = urcfg.getPolicy(); | |||||
if (policy != null) { | |||||
ur.setPolicy(policy); | |||||
// 如果请求中设置了策略,才进行更新; | |||||
RolesPolicy policy = urcfg.getPolicy(); | |||||
if (policy != null) { | |||||
ur.setPolicy(policy); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -26,8 +26,8 @@ public interface UserAuthorizeOperation extends Operation { | |||||
* | * | ||||
* @return | * @return | ||||
*/ | */ | ||||
@DataField(order = 0, primitiveType = PrimitiveType.BYTES) | |||||
Bytes getUserAddress(); | |||||
@DataField(order = 0, primitiveType = PrimitiveType.BYTES, list = true) | |||||
Bytes[] getUserAddresses(); | |||||
/** | /** | ||||
* 要更新的多角色权限策略; | * 要更新的多角色权限策略; | ||||
@@ -5,8 +5,8 @@ import com.jd.blockchain.utils.Bytes; | |||||
public interface UserAuthorize { | public interface UserAuthorize { | ||||
UserRolesAuthorizer forUser(BlockchainIdentity userId); | |||||
UserRolesAuthorizer forUser(BlockchainIdentity... userId); | |||||
UserRolesAuthorizer forUser(Bytes userAddress); | |||||
UserRolesAuthorizer forUser(Bytes... userAddress); | |||||
} | } |
@@ -1,9 +1,8 @@ | |||||
package com.jd.blockchain.transaction; | package com.jd.blockchain.transaction; | ||||
import java.util.Arrays; | |||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.LinkedHashMap; | |||||
import java.util.LinkedHashSet; | import java.util.LinkedHashSet; | ||||
import java.util.Map; | |||||
import java.util.Set; | import java.util.Set; | ||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
@@ -21,8 +20,8 @@ public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOpe | |||||
DataContractRegistry.register(UserRegisterOperation.class); | DataContractRegistry.register(UserRegisterOperation.class); | ||||
} | } | ||||
private Map<Bytes, UserRolesAuthorization> userAuthMap = Collections | |||||
.synchronizedMap(new LinkedHashMap<Bytes, UserRolesAuthorization>()); | |||||
private Set<UserRolesAuthorization> userAuthMap = Collections | |||||
.synchronizedSet(new LinkedHashSet<UserRolesAuthorization>()); | |||||
public UserAuthorizeOpTemplate() { | public UserAuthorizeOpTemplate() { | ||||
} | } | ||||
@@ -32,7 +31,7 @@ public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOpe | |||||
@Override | @Override | ||||
public UserRolesAuthorization[] getUserRolesAuthorizations() { | public UserRolesAuthorization[] getUserRolesAuthorizations() { | ||||
return ArrayUtils.toArray(userAuthMap.values(), UserRolesAuthorization.class); | |||||
return ArrayUtils.toArray(userAuthMap, UserRolesAuthorization.class); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -41,35 +40,33 @@ public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOpe | |||||
} | } | ||||
@Override | @Override | ||||
public UserRolesAuthorizer forUser(Bytes userAddress) { | |||||
UserRolesAuthorization userRolesAuth = userAuthMap.get(userAddress); | |||||
if (userRolesAuth == null) { | |||||
userRolesAuth = new UserRolesAuthorization(userAddress); | |||||
userAuthMap.put(userAddress, userRolesAuth); | |||||
} | |||||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||||
UserRolesAuthorization userRolesAuth = new UserRolesAuthorization(userAddresses); | |||||
userAuthMap.add(userRolesAuth); | |||||
return userRolesAuth; | return userRolesAuth; | ||||
} | } | ||||
@Override | @Override | ||||
public UserRolesAuthorizer forUser(BlockchainIdentity userId) { | |||||
return forUser(userId.getAddress()); | |||||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||||
Bytes[] addresses = Arrays.stream(userIds).map(p -> p.getAddress()).toArray(Bytes[]::new); | |||||
return forUser(addresses); | |||||
} | } | ||||
private class UserRolesAuthorization implements UserRolesAuthorizer, UserRolesEntry { | private class UserRolesAuthorization implements UserRolesAuthorizer, UserRolesEntry { | ||||
private Bytes userAddress; | |||||
private Bytes[] userAddress; | |||||
private RolesPolicy policy = RolesPolicy.UNION; | private RolesPolicy policy = RolesPolicy.UNION; | ||||
private Set<String> authRoles = new LinkedHashSet<String>(); | private Set<String> authRoles = new LinkedHashSet<String>(); | ||||
private Set<String> unauthRoles = new LinkedHashSet<String>(); | private Set<String> unauthRoles = new LinkedHashSet<String>(); | ||||
private UserRolesAuthorization(Bytes userAddress) { | |||||
private UserRolesAuthorization(Bytes[] userAddress) { | |||||
this.userAddress = userAddress; | this.userAddress = userAddress; | ||||
} | } | ||||
@Override | @Override | ||||
public Bytes getUserAddress() { | |||||
public Bytes[] getUserAddresses() { | |||||
return userAddress; | return userAddress; | ||||
} | } | ||||
@@ -119,13 +116,13 @@ public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOpe | |||||
} | } | ||||
@Override | @Override | ||||
public UserRolesAuthorizer forUser(BlockchainIdentity userId) { | |||||
return UserAuthorizeOpTemplate.this.forUser(userId); | |||||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||||
return UserAuthorizeOpTemplate.this.forUser(userIds); | |||||
} | } | ||||
@Override | @Override | ||||
public UserRolesAuthorizer forUser(Bytes userAddress) { | |||||
return UserAuthorizeOpTemplate.this.forUser(userAddress); | |||||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||||
return UserAuthorizeOpTemplate.this.forUser(userAddresses); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -65,7 +65,7 @@ com.jd.blockchain.crypto.service.sm.SMCryptoService | |||||
crypto.verify-hash=true | crypto.verify-hash=true | ||||
#哈希算法; | #哈希算法; | ||||
crypto.hash-algorithm=SHA256; | |||||
crypto.hash-algorithm=SHA256 | |||||
#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | #参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | ||||
@@ -20,60 +20,67 @@ import com.jd.blockchain.utils.ConsoleUtils; | |||||
/** | /** | ||||
* 注册用户 | * 注册用户 | ||||
* | |||||
* @author shaozhuguang | * @author shaozhuguang | ||||
* @create 2018/10/18 | * @create 2018/10/18 | ||||
* @since 1.0.0 | * @since 1.0.0 | ||||
*/ | */ | ||||
public class SDKDemo_RegisterUser { | public class SDKDemo_RegisterUser { | ||||
public static void main(String[] args) { | |||||
public static void main(String[] args) { | |||||
String GATEWAY_IPADDR = "127.0.0.1"; | |||||
int GATEWAY_PORT = 8081; | |||||
if (args != null && args.length == 2) { | |||||
GATEWAY_IPADDR = args[0]; | |||||
GATEWAY_PORT = Integer.parseInt(args[1]); | |||||
} | |||||
String GATEWAY_IPADDR = "127.0.0.1"; | |||||
int GATEWAY_PORT = 8081; | |||||
if (args != null && args.length == 2) { | |||||
GATEWAY_IPADDR = args[0]; | |||||
GATEWAY_PORT = Integer.parseInt(args[1]); | |||||
} | |||||
// 注册相关class | |||||
DataContractRegistry.register(TransactionContent.class); | |||||
DataContractRegistry.register(TransactionContentBody.class); | |||||
DataContractRegistry.register(TransactionRequest.class); | |||||
DataContractRegistry.register(NodeRequest.class); | |||||
DataContractRegistry.register(EndpointRequest.class); | |||||
DataContractRegistry.register(TransactionResponse.class); | |||||
// 注册相关class | |||||
DataContractRegistry.register(TransactionContent.class); | |||||
DataContractRegistry.register(TransactionContentBody.class); | |||||
DataContractRegistry.register(TransactionRequest.class); | |||||
DataContractRegistry.register(NodeRequest.class); | |||||
DataContractRegistry.register(EndpointRequest.class); | |||||
DataContractRegistry.register(TransactionResponse.class); | |||||
PrivKey privKey = SDKDemo_Params.privkey1; | |||||
PubKey pubKey = SDKDemo_Params.pubKey1; | |||||
PrivKey privKey = SDKDemo_Params.privkey1; | |||||
PubKey pubKey = SDKDemo_Params.pubKey1; | |||||
BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); | |||||
BlockchainKeypair CLIENT_CERT = new BlockchainKeypair(SDKDemo_Params.pubKey0, SDKDemo_Params.privkey0); | |||||
boolean SECURE = false; | |||||
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, | |||||
CLIENT_CERT); | |||||
BlockchainService service = serviceFactory.getBlockchainService(); | |||||
boolean SECURE = false; | |||||
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IPADDR, GATEWAY_PORT, SECURE, | |||||
CLIENT_CERT); | |||||
BlockchainService service = serviceFactory.getBlockchainService(); | |||||
HashDigest[] ledgerHashs = service.getLedgerHashs(); | |||||
// 在本地定义注册账号的 TX; | |||||
TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); | |||||
HashDigest[] ledgerHashs = service.getLedgerHashs(); | |||||
// 在本地定义注册账号的 TX; | |||||
TransactionTemplate txTemp = service.newTransaction(ledgerHashs[0]); | |||||
//existed signer | |||||
AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); | |||||
// existed signer | |||||
AsymmetricKeypair keyPair = new BlockchainKeypair(pubKey, privKey); | |||||
BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); | |||||
BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); | |||||
// 注册 | |||||
txTemp.users().register(user.getIdentity()); | |||||
// 注册 | |||||
txTemp.users().register(user.getIdentity()); | |||||
// TX 准备就绪; | |||||
PreparedTransaction prepTx = txTemp.prepare(); | |||||
// 定义角色权限; | |||||
txTemp.security().roles().configure("MANAGER") | |||||
.enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) | |||||
.enable(TransactionPermission.CONTRACT_OPERATION); | |||||
txTemp.security().authorziations().forUser(user.getIdentity()).authorize("MANAGER"); | |||||
// 使用私钥进行签名; | |||||
prepTx.sign(keyPair); | |||||
// TX 准备就绪; | |||||
PreparedTransaction prepTx = txTemp.prepare(); | |||||
// 提交交易; | |||||
TransactionResponse transactionResponse = prepTx.commit(); | |||||
// 使用私钥进行签名; | |||||
prepTx.sign(keyPair); | |||||
ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); | |||||
} | |||||
// 提交交易; | |||||
TransactionResponse transactionResponse = prepTx.commit(); | |||||
ConsoleUtils.info("register user complete, result is [%s]", transactionResponse.isSuccess()); | |||||
} | |||||
} | } |
@@ -8,6 +8,48 @@ ledger.name=TEST-LEDGER | |||||
#声明的账本创建时间;格式为 “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 | ||||
@@ -18,6 +60,12 @@ consensus.conf=classpath: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 | ||||
@@ -27,6 +75,10 @@ cons_parti.0.name=jd.com | |||||
cons_parti.0.pubkey-path=keys/jd-com.pub | cons_parti.0.pubkey-path=keys/jd-com.pub | ||||
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 | cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 | ||||
#第0个参与方的角色清单;可选项; | |||||
cons_parti.0.roles=ADMIN, MANAGER | |||||
#第0个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
cons_parti.0.roles-policy=UNION | |||||
#第0个参与方的共识服务的主机地址; | #第0个参与方的共识服务的主机地址; | ||||
cons_parti.0.consensus.host=127.0.0.1 | cons_parti.0.consensus.host=127.0.0.1 | ||||
#第0个参与方的共识服务的端口; | #第0个参与方的共识服务的端口; | ||||
@@ -46,6 +98,10 @@ cons_parti.1.name=at.com | |||||
cons_parti.1.pubkey-path=keys/at-com.pub | cons_parti.1.pubkey-path=keys/at-com.pub | ||||
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX | cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX | ||||
#第1个参与方的角色清单;可选项; | |||||
cons_parti.1.roles=MANAGER | |||||
#第1个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
cons_parti.1.roles-policy=UNION | |||||
#第1个参与方的共识服务的主机地址; | #第1个参与方的共识服务的主机地址; | ||||
cons_parti.1.consensus.host=127.0.0.1 | cons_parti.1.consensus.host=127.0.0.1 | ||||
#第1个参与方的共识服务的端口; | #第1个参与方的共识服务的端口; | ||||
@@ -65,6 +121,10 @@ cons_parti.2.name=bt.com | |||||
cons_parti.2.pubkey-path=keys/bt-com.pub | cons_parti.2.pubkey-path=keys/bt-com.pub | ||||
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x | cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x | ||||
#第2个参与方的角色清单;可选项; | |||||
cons_parti.2.roles=MANAGER | |||||
#第2个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
cons_parti.2.roles-policy=UNION | |||||
#第2个参与方的共识服务的主机地址; | #第2个参与方的共识服务的主机地址; | ||||
cons_parti.2.consensus.host=127.0.0.1 | cons_parti.2.consensus.host=127.0.0.1 | ||||
#第2个参与方的共识服务的端口; | #第2个参与方的共识服务的端口; | ||||
@@ -84,6 +144,10 @@ cons_parti.3.name=xt.com | |||||
cons_parti.3.pubkey-path=keys/xt-com.pub | cons_parti.3.pubkey-path=keys/xt-com.pub | ||||
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | ||||
cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk | cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk | ||||
#第3个参与方的角色清单;可选项; | |||||
cons_parti.3.roles=GUEST | |||||
#第3个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; | |||||
cons_parti.3.roles-policy=INTERSECT | |||||
#第3个参与方的共识服务的主机地址; | #第3个参与方的共识服务的主机地址; | ||||
cons_parti.3.consensus.host=127.0.0.1 | cons_parti.3.consensus.host=127.0.0.1 | ||||
#第3个参与方的共识服务的端口; | #第3个参与方的共识服务的端口; | ||||
@@ -9,6 +9,7 @@ import java.util.*; | |||||
*/ | */ | ||||
public abstract class ArrayUtils { | public abstract class ArrayUtils { | ||||
private ArrayUtils() { | private ArrayUtils() { | ||||
} | } | ||||
public static <T> T[] singleton(T obj, Class<T> clazz) { | public static <T> T[] singleton(T obj, Class<T> clazz) { | ||||