@@ -290,6 +290,10 @@ public class LedgerAdminDataset implements Transactional, LedgerAdminInfo { | |||
return participants.getParticipants(); | |||
} | |||
ParticipantDataset getParticipantDataset() { | |||
return participants; | |||
} | |||
/** | |||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||
* | |||
@@ -30,7 +30,7 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerRepositoryImpl implements LedgerRepository { | |||
class LedgerRepositoryImpl implements LedgerRepository { | |||
private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); | |||
@@ -422,7 +422,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
private LedgerDataset innerGetLedgerDataset(LedgerBlock block) { | |||
LedgerAdminDataset adminDataset = createAdminDataset(block); | |||
CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); | |||
UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); | |||
DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); | |||
ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); | |||
@@ -2,37 +2,12 @@ package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.ledger.LedgerPrivilege; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* | |||
* {@link LedgerSecurityManager} implements the functions of security | |||
* management, including authentication, authorization, data confidentiality, | |||
* etc. | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerSecurityManager { | |||
public static final String ANONYMOUS_ROLE = "_ANONYMOUS"; | |||
public static final String DEFAULT_ROLE = "_DEFAULT"; | |||
public Set<String> getRoleNames(){ | |||
throw new IllegalStateException("Not implemented!"); | |||
} | |||
public RolePrivileges setRole(String role, LedgerPrivilege privilege) { | |||
throw new IllegalStateException("Not implemented!"); | |||
} | |||
public interface LedgerSecurityManager { | |||
public RolePrivileges getRole(String role) { | |||
throw new IllegalStateException("Not implemented!"); | |||
} | |||
} | |||
String DEFAULT_ROLE = "_DEFAULT"; | |||
SecurityPolicy getSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes); | |||
} |
@@ -0,0 +1,287 @@ | |||
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.Set; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.UserRoleSettings; | |||
import com.jd.blockchain.ledger.UserRoles; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 账本安全管理器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerSecurityManagerImpl implements LedgerSecurityManager { | |||
private RolePrivilegeSettings rolePrivilegeSettings; | |||
private UserRoleSettings userRolesSettings; | |||
private Map<Bytes, UserRolesPrivileges> userPrivilegesCache = new ConcurrentHashMap<>(); | |||
private Map<Bytes, UserRoles> userRolesCache = new ConcurrentHashMap<>(); | |||
private Map<String, RolePrivileges> rolesPrivilegeCache = new ConcurrentHashMap<>(); | |||
public LedgerSecurityManagerImpl(RolePrivilegeSettings rolePrivilegeSettings, UserRoleSettings userRolesSettings) { | |||
this.rolePrivilegeSettings = rolePrivilegeSettings; | |||
this.userRolesSettings = userRolesSettings; | |||
} | |||
@Override | |||
public SecurityPolicy getSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||
Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap = new HashMap<>(); | |||
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap = new HashMap<>(); | |||
for (Bytes userAddress : endpoints) { | |||
UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); | |||
endpointPrivilegeMap.put(userAddress, userPrivileges); | |||
} | |||
for (Bytes userAddress : nodes) { | |||
UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); | |||
nodePrivilegeMap.put(userAddress, userPrivileges); | |||
} | |||
return new UserRolesSecurityPolicy(endpointPrivilegeMap, nodePrivilegeMap); | |||
} | |||
private UserRolesPrivileges getUserRolesPrivilegs(Bytes userAddress) { | |||
UserRolesPrivileges userPrivileges = userPrivilegesCache.get(userAddress); | |||
if (userPrivileges != null) { | |||
return userPrivileges; | |||
} | |||
UserRoles userRoles = null; | |||
List<RolePrivileges> privilegesList = new ArrayList<>(); | |||
// 加载用户的角色列表; | |||
userRoles = userRolesCache.get(userAddress); | |||
if (userRoles == null) { | |||
userRoles = userRolesSettings.getUserRoles(userAddress); | |||
if (userRoles != null) { | |||
userRolesCache.put(userAddress, userRoles); | |||
} | |||
} | |||
// 计算用户的综合权限; | |||
if (userRoles != null) { | |||
String[] roles = userRoles.getRoles(); | |||
RolePrivileges privilege = null; | |||
for (String role : roles) { | |||
// 先从缓存读取,如果没有再从原始数据源进行加载; | |||
privilege = rolesPrivilegeCache.get(role); | |||
if (privilege == null) { | |||
privilege = rolePrivilegeSettings.getRolePrivilege(role); | |||
if (privilege == null) { | |||
// 略过不存在的无效角色; | |||
continue; | |||
} | |||
rolesPrivilegeCache.put(role, privilege); | |||
} | |||
privilegesList.add(privilege); | |||
} | |||
} | |||
// 如果用户未被授权任何角色,则采用默认角色的权限; | |||
if (privilegesList.size() == 0) { | |||
RolePrivileges privilege = getDefaultRolePrivilege(); | |||
privilegesList.add(privilege); | |||
} | |||
if (userRoles == null) { | |||
userPrivileges = new UserRolesPrivileges(userAddress, RolesPolicy.UNION, privilegesList); | |||
} else { | |||
userPrivileges = new UserRolesPrivileges(userAddress, userRoles.getPolicy(), privilegesList); | |||
} | |||
userPrivilegesCache.put(userAddress, userPrivileges); | |||
return userPrivileges; | |||
} | |||
private RolePrivileges getDefaultRolePrivilege() { | |||
RolePrivileges privileges = rolesPrivilegeCache.get(DEFAULT_ROLE); | |||
if (privileges == null) { | |||
privileges = rolePrivilegeSettings.getRolePrivilege(DEFAULT_ROLE); | |||
if (privileges == null) { | |||
throw new LedgerSecurityException( | |||
"This ledger is missing the default role-privilege settings for the users who don't have a role!"); | |||
} | |||
} | |||
return privileges; | |||
} | |||
private class UserRolesSecurityPolicy implements SecurityPolicy { | |||
/** | |||
* 终端用户的权限表; | |||
*/ | |||
private Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap = new HashMap<>(); | |||
/** | |||
* 节点参与方的权限表; | |||
*/ | |||
private Map<Bytes, UserRolesPrivileges> nodePrivilegeMap = new HashMap<>(); | |||
public UserRolesSecurityPolicy(Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap, | |||
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap) { | |||
this.endpointPrivilegeMap = endpointPrivilegeMap; | |||
this.nodePrivilegeMap = nodePrivilegeMap; | |||
} | |||
@Override | |||
public boolean isEnableToEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) { | |||
if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||
if (p.getLedgerPrivileges().isEnable(permission)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIdsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||
if (!p.getLedgerPrivileges().isEnable(permission)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public boolean isEnableToEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) { | |||
if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||
if (p.getTransactionPrivileges().isEnable(permission)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIdsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { | |||
if (!p.getTransactionPrivileges().isEnable(permission)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public boolean isEnableToNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) { | |||
if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||
if (p.getLedgerPrivileges().isEnable(permission)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIdsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||
if (!p.getLedgerPrivileges().isEnable(permission)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public boolean isEnableToNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) { | |||
if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||
if (p.getTransactionPrivileges().isEnable(permission)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIdsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (UserRolesPrivileges p : nodePrivilegeMap.values()) { | |||
if (!p.getTransactionPrivileges().isEnable(permission)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public void checkEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isEnableToEndpoints(permission, midPolicy)) { | |||
throw new LedgerSecurityException(String.format( | |||
"The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", | |||
permission, midPolicy)); | |||
} | |||
} | |||
@Override | |||
public void checkEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isEnableToEndpoints(permission, midPolicy)) { | |||
throw new LedgerSecurityException(String.format( | |||
"The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", | |||
permission, midPolicy)); | |||
} | |||
} | |||
@Override | |||
public void checkNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException { | |||
if (!isEnableToNodes(permission, midPolicy)) { | |||
throw new LedgerSecurityException(String.format( | |||
"The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", | |||
permission, midPolicy)); | |||
} | |||
} | |||
@Override | |||
public void checkNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isEnableToNodes(permission, midPolicy)) { | |||
throw new LedgerSecurityException(String.format( | |||
"The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", | |||
permission, midPolicy)); | |||
} | |||
} | |||
@Override | |||
public Set<Bytes> getEndpoints() { | |||
return endpointPrivilegeMap.keySet(); | |||
} | |||
@Override | |||
public Set<Bytes> getNodes() { | |||
return nodePrivilegeMap.keySet(); | |||
} | |||
} | |||
} |
@@ -214,32 +214,9 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
return ledgerHash.equals(reqLedgerHash); | |||
} | |||
private boolean verifyTxContent(TransactionRequest request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
return false; | |||
} | |||
DigitalSignature[] endpointSignatures = request.getEndpointSignatures(); | |||
if (endpointSignatures != null) { | |||
for (DigitalSignature signature : endpointSignatures) { | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), | |||
signature.getPubKey())) { | |||
return false; | |||
} | |||
} | |||
} | |||
DigitalSignature[] nodeSignatures = request.getNodeSignatures(); | |||
if (nodeSignatures != null) { | |||
for (DigitalSignature signature : nodeSignatures) { | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), | |||
signature.getPubKey())) { | |||
return false; | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* 注:此方法不验证交易完整性和签名有效性,仅仅设计为进行交易记录的管理;调用者应在此方法之外进行数据完整性和签名有效性的检查; | |||
*/ | |||
@Override | |||
public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | |||
// if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { | |||
@@ -250,15 +227,6 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
TransactionState.IGNORED_BY_WRONG_LEDGER); | |||
} | |||
// TODO: 把验签和创建交易并行化; | |||
// if (SettingContext.txSettings().verifySignature() && !verifyTxContent(txRequest)) { | |||
if (!verifyTxContent(txRequest)) { | |||
// 抛弃哈希和签名校验失败的交易请求; | |||
throw new IllegalTransactionException( | |||
"Wrong transaction signature! --[TxHash=" + txRequest.getTransactionContent().getHash() + "]!", | |||
TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
} | |||
if (currentTxCtx != null) { | |||
throw new IllegalStateException( | |||
"Unable to open another new transaction before the current transaction is completed! --[TxHash=" | |||
@@ -0,0 +1,21 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* 多身份的权限校验策略; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum MultiIdsPolicy { | |||
/** | |||
* 至少有一个都能通过; | |||
*/ | |||
AT_LEAST_ONE, | |||
/** | |||
* 每一个都能通过; | |||
*/ | |||
ALL | |||
} |
@@ -3,7 +3,6 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.Operation; | |||
public interface OperationHandle { | |||
/** | |||
@@ -18,36 +17,16 @@ public interface OperationHandle { | |||
* 同步解析和执行操作; | |||
* | |||
* | |||
* @param op | |||
* 操作实例; | |||
* @param newBlockDataset | |||
* 需要修改的新区块的数据集; | |||
* @param requestContext | |||
* 交易请求上下文; | |||
* @param previousBlockDataset | |||
* 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param op 操作实例; | |||
* @param newBlockDataset 需要修改的新区块的数据集; | |||
* @param requestContext 交易请求上下文; | |||
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;注:此数据集是只读的; | |||
* | |||
* @return 操作执行结果 | |||
* @param handleContext 操作上下文;` | |||
* @param ledgerService | |||
* @return | |||
*/ | |||
BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestContext requestContext, | |||
BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||
// /** | |||
// * 异步解析和执行操作; | |||
// * TODO 未来规划实现 | |||
// * | |||
// * | |||
// * @param op | |||
// * 操作实例; | |||
// * @param newBlockDataset | |||
// * 需要修改的新区块的数据集; | |||
// * @param requestContext | |||
// * 交易请求上下文; | |||
// * @param previousBlockDataset | |||
// * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
// * | |||
// * @return 操作执行结果 | |||
// */ | |||
// AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, | |||
// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||
} |
@@ -2,8 +2,14 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.Operation; | |||
/** | |||
* 在交易处理过程中,提供对多种交易操作处理器互相调用的机制; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface OperationHandleContext { | |||
void handle(Operation operation); | |||
} |
@@ -77,6 +77,12 @@ public class ParticipantDataset implements Transactional, MerkleProvable { | |||
return address; | |||
} | |||
public boolean contains(Bytes address) { | |||
Bytes key = encodeKey(address); | |||
long latestVersion = dataset.getVersion(key); | |||
return latestVersion > -1; | |||
} | |||
/** | |||
* 返回指定地址的参与方凭证; | |||
* | |||
@@ -7,6 +7,7 @@ import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerPrivilege; | |||
import com.jd.blockchain.ledger.PrivilegeSet; | |||
import com.jd.blockchain.ledger.Privileges; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
@@ -61,9 +62,11 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role | |||
return dataset.getDataCount(); | |||
} | |||
/** | |||
* | |||
*/ | |||
@Override | |||
public long addRolePrivilege(String roleName, Privileges privileges) { | |||
return addRolePrivilege(roleName, privileges.getLedgerPrivilege(), privileges.getTransactionPrivilege()); | |||
} | |||
@Override | |||
public long addRolePrivilege(String roleName, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | |||
RolePrivileges roleAuth = new RolePrivileges(roleName, -1, ledgerPrivilege, txPrivilege); | |||
@@ -0,0 +1,38 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
public class SecurityContext { | |||
private static ThreadLocal<SecurityPolicy> policyHolder = new ThreadLocal<SecurityPolicy>(); | |||
public static void setContextUsersPolicy(SecurityPolicy policy) { | |||
policyHolder.set(policy); | |||
} | |||
public static SecurityPolicy removeContextUsersPolicy() { | |||
SecurityPolicy p = policyHolder.get(); | |||
policyHolder.remove(); | |||
return p; | |||
} | |||
public static SecurityPolicy getContextUsersPolicy() { | |||
return policyHolder.get(); | |||
} | |||
/** | |||
* 把上下文安全策略切换为指定的策略,并执行参数指定的 {@link Runnable} 操作,当操作完成后恢复原来的上下文策略; | |||
* | |||
* @param contextUsersPolicy | |||
* @param runnable | |||
*/ | |||
public static void switchContextUsersPolicy(SecurityPolicy contextUsersPolicy, Runnable runnable) { | |||
} | |||
} |
@@ -0,0 +1,109 @@ | |||
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.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 针对特定交易请求的账本安全策略; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface SecurityPolicy { | |||
/** | |||
* 签署交易的终端用户的地址列表;(来自{@link TransactionRequest#getEndpointSignatures()}) | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getEndpoints(); | |||
/** | |||
* 签署交易的节点参与方的地址列表(来自{@link TransactionRequest#getNodeSignatures()}) | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getNodes(); | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEnableToEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEnableToEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEnableToNodes(LedgerPermission permission, MultiIdsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEnableToNodes(TransactionPermission permission, MultiIdsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
@@ -15,24 +16,32 @@ import com.jd.blockchain.ledger.DataAccountDoesNotExistException; | |||
import com.jd.blockchain.ledger.IllegalTransactionException; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.OperationResultData; | |||
import com.jd.blockchain.ledger.ParticipantDoesNotExistException; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionRollbackException; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.UserDoesNotExistException; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension.Credential; | |||
import com.jd.blockchain.service.TransactionBatchProcess; | |||
import com.jd.blockchain.service.TransactionBatchResult; | |||
import com.jd.blockchain.service.TransactionBatchResultHandle; | |||
import com.jd.blockchain.transaction.SignatureUtils; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.transaction.TxResponseMessage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); | |||
private LedgerSecurityManager securityManager; | |||
private LedgerService ledgerService; | |||
private LedgerEditor newBlockEditor; | |||
@@ -55,8 +64,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param opHandles 操作处理对象注册表; | |||
*/ | |||
public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataset previousBlockDataset, | |||
OperationHandleRegisteration opHandles, LedgerService ledgerService) { | |||
public TransactionBatchProcessor(LedgerSecurityManager securityManager, LedgerEditor newBlockEditor, | |||
LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, LedgerService ledgerService) { | |||
this.securityManager = securityManager; | |||
this.newBlockEditor = newBlockEditor; | |||
this.previousBlockDataset = previousBlockDataset; | |||
this.opHandles = opHandles; | |||
@@ -76,12 +86,26 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
try { | |||
LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
TransactionRequestExtension reqExt = new TransactionRequestExtensionImpl(request); | |||
// 初始化交易的用户安全策略; | |||
SecurityPolicy securityPolicy = securityManager.getSecurityPolicy(reqExt.getEndpointAddresses(), | |||
reqExt.getNodeAddresses()); | |||
SecurityContext.setContextUsersPolicy(securityPolicy); | |||
// 安全校验; | |||
checkSecurity(); | |||
// 验证交易请求; | |||
checkRequest(reqExt); | |||
// 创建交易上下文; | |||
// 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; | |||
LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); | |||
// 处理交易; | |||
resp = handleTx(request, txCtx); | |||
resp = handleTx(reqExt, txCtx); | |||
LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
@@ -93,10 +117,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
"Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (BlockRollbackException e) { | |||
// 抛弃发生处理异常的交易请求; | |||
// resp = discard(request, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); | |||
// 发生区块级别的处理异常,向上重新抛出异常进行处理,整个区块可能被丢弃; | |||
LOGGER.error(String.format( | |||
"Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
@@ -110,12 +133,86 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} finally { | |||
// 清空交易的用户安全策略; | |||
SecurityContext.removeContextUsersPolicy(); | |||
} | |||
responseList.add(resp); | |||
return resp; | |||
} | |||
/** | |||
* 验证交易的参与方的权限; | |||
*/ | |||
private void checkSecurity() { | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
// 验证当前交易请求的节点参与方是否具有权限; | |||
securityPolicy.checkNodes(LedgerPermission.APPROVE_TX, MultiIdsPolicy.AT_LEAST_ONE); | |||
} | |||
private void checkRequest(TransactionRequestExtension reqExt) { | |||
// TODO: 把验签和创建交易并行化; | |||
checkTxContent(reqExt); | |||
checkEndpointSignatures(reqExt); | |||
checkNodeSignatures(reqExt); | |||
} | |||
private void checkTxContent(TransactionRequestExtension requestExt) { | |||
TransactionContent txContent = requestExt.getTransactionContent(); | |||
if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
// 由于哈希校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
throw new IllegalTransactionException( | |||
"Wrong transaction content hash! --[TxHash=" + requestExt.getTransactionContent().getHash() + "]!", | |||
TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
} | |||
} | |||
private void checkEndpointSignatures(TransactionRequestExtension request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
Collection<Credential> endpoints = request.getEndpoints(); | |||
if (endpoints != null) { | |||
for (Credential endpoint : endpoints) { | |||
if (!previousBlockDataset.getUserAccountSet().contains(endpoint.getAddress())) { | |||
throw new UserDoesNotExistException( | |||
"The endpoint signer[" + endpoint.getAddress() + "] was not registered!"); | |||
} | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), endpoint.getSignature().getDigest(), | |||
endpoint.getPubKey())) { | |||
// 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
throw new IllegalTransactionException( | |||
String.format("Wrong transaction endpoint signature! --[Tx Hash=%s][Endpoint Signer=%s]!", | |||
request.getTransactionContent().getHash(), endpoint.getAddress()), | |||
TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
} | |||
} | |||
} | |||
} | |||
private void checkNodeSignatures(TransactionRequestExtension request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
Collection<Credential> nodes = request.getNodes(); | |||
if (nodes != null) { | |||
for (Credential node : nodes) { | |||
if (!previousBlockDataset.getAdminDataset().getParticipantDataset().contains(node.getAddress())) { | |||
throw new ParticipantDoesNotExistException( | |||
"The node signer[" + node.getAddress() + "] was not registered to the participant set!"); | |||
} | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), node.getSignature().getDigest(), | |||
node.getPubKey())) { | |||
// 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
throw new IllegalTransactionException( | |||
String.format("Wrong transaction node signature! --[Tx Hash=%s][Node Signer=%s]!", | |||
request.getTransactionContent().getHash(), node.getAddress()), | |||
TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* 处理交易;<br> | |||
* | |||
@@ -125,23 +222,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
* @param txCtx | |||
* @return | |||
*/ | |||
private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) { | |||
private TransactionResponse handleTx(TransactionRequestExtension request, LedgerTransactionContext txCtx) { | |||
TransactionState result; | |||
List<OperationResult> operationResults = new ArrayList<>(); | |||
try { | |||
LedgerDataset dataset = txCtx.getDataset(); | |||
TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); | |||
// TODO: 验证签名者的有效性; | |||
for (Bytes edpAddr : reqCtx.getEndpoints()) { | |||
if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { | |||
throw new LedgerException("The endpoint signer[" + edpAddr + "] was not registered!"); | |||
} | |||
} | |||
for (Bytes edpAddr : reqCtx.getNodes()) { | |||
if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { | |||
throw new LedgerException("The node signer[" + edpAddr + "] was not registered!"); | |||
} | |||
} | |||
// 执行操作; | |||
Operation[] ops = request.getTransactionContent().getOperations(); | |||
@@ -151,14 +236,14 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
// assert; Instance of operation are one of User related operations or | |||
// DataAccount related operations; | |||
OperationHandle hdl = opHandles.getHandle(operation.getClass()); | |||
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); | |||
hdl.process(operation, dataset, request, previousBlockDataset, this, ledgerService); | |||
} | |||
}; | |||
OperationHandle opHandle; | |||
int opIndex = 0; | |||
for (Operation op : ops) { | |||
opHandle = opHandles.getHandle(op.getClass()); | |||
BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, | |||
BytesValue opResult = opHandle.process(op, dataset, request, previousBlockDataset, handleContext, | |||
ledgerService); | |||
if (opResult != null) { | |||
operationResults.add(new OperationResultData(opIndex, opResult)); | |||
@@ -177,6 +262,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (BlockRollbackException e) { | |||
// 回滚整个区块; | |||
result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; | |||
txCtx.rollback(); | |||
LOGGER.error( | |||
@@ -195,17 +281,27 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
result = TransactionState.USER_DOES_NOT_EXIST; | |||
} else if (e instanceof ContractDoesNotExistException) { | |||
result = TransactionState.CONTRACT_DOES_NOT_EXIST; | |||
} else if (e instanceof ParticipantDoesNotExistException) { | |||
result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; | |||
} | |||
txCtx.discardAndCommit(result, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to ledger exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
"Due to ledger exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (LedgerSecurityException e) { | |||
// TODO: 识别更详细的异常类型以及执行对应的处理; | |||
result = TransactionState.REJECTED_BY_SECURITY_POLICY; | |||
txCtx.discardAndCommit(result, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to ledger security exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (Exception e) { | |||
result = TransactionState.SYSTEM_ERROR; | |||
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to system exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
"Due to system exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} | |||
@@ -41,8 +41,12 @@ public class TransactionEngineImpl implements TransactionEngine { | |||
LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(ledgerBlock); | |||
batch = new InnerTransactionBatchProcessor(ledgerHash, newBlockEditor, previousBlockDataset, opHdlRegs, | |||
ledgerService, ledgerBlock.getHeight()); | |||
LedgerAdminDataset previousAdminDataset = previousBlockDataset.getAdminDataset(); | |||
LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl(previousAdminDataset.getRolePrivileges(), | |||
previousAdminDataset.getUserRoles()); | |||
batch = new InnerTransactionBatchProcessor(ledgerHash, securityManager, newBlockEditor, previousBlockDataset, | |||
opHdlRegs, ledgerService, ledgerBlock.getHeight()); | |||
batchs.put(ledgerHash, batch); | |||
return batch; | |||
} | |||
@@ -65,19 +69,15 @@ public class TransactionEngineImpl implements TransactionEngine { | |||
/** | |||
* 创建交易批处理器; | |||
* | |||
* @param ledgerHash | |||
* 账本哈希; | |||
* @param newBlockEditor | |||
* 新区块的数据编辑器; | |||
* @param previousBlockDataset | |||
* 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param opHandles | |||
* 操作处理对象注册表; | |||
* @param ledgerHash 账本哈希; | |||
* @param newBlockEditor 新区块的数据编辑器; | |||
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param opHandles 操作处理对象注册表; | |||
*/ | |||
public InnerTransactionBatchProcessor(HashDigest ledgerHash, LedgerEditor newBlockEditor, | |||
LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, | |||
public InnerTransactionBatchProcessor(HashDigest ledgerHash, LedgerSecurityManager securityManager, | |||
LedgerEditor newBlockEditor, LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, | |||
LedgerService ledgerService, long blockHeight) { | |||
super(newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||
super(securityManager, newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||
this.ledgerHash = ledgerHash; | |||
this.blockHeight = blockHeight; | |||
} | |||
@@ -1,70 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 交易请求上下文; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionRequestContext { | |||
/** | |||
* 交易请求; | |||
* | |||
* @return | |||
*/ | |||
TransactionRequest getRequest(); | |||
/** | |||
* 签名发起请求的终端用户的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getEndpoints(); | |||
/** | |||
* 签名发起请求的节点的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getNodes(); | |||
/** | |||
* 请求的终端发起人列表中是否包含指定地址的终端用户; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsEndpoint(Bytes address); | |||
/** | |||
* 请求的经手节点列表中是否包含指定地址的节点; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsNode(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的终端的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getEndpointSignature(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的节点的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getNodeSignature(Bytes address); | |||
} |
@@ -1,79 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* @Author zhaogw | |||
* @Date 2018/9/5 14:52 | |||
*/ | |||
public class TransactionRequestContextImpl implements TransactionRequestContext { | |||
private TransactionRequest request; | |||
private Map<Bytes, DigitalSignature> endpointSignatures = new HashMap<>(); | |||
private Map<Bytes, DigitalSignature> nodeSignatures = new HashMap<>(); | |||
public TransactionRequestContextImpl(TransactionRequest request) { | |||
this.request = request; | |||
resolveSigners(); | |||
} | |||
private void resolveSigners() { | |||
if (request.getEndpointSignatures() != null) { | |||
for (DigitalSignature signature : request.getEndpointSignatures()) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
endpointSignatures.put(address, signature); | |||
} | |||
} | |||
if (request.getEndpointSignatures() != null) { | |||
for (DigitalSignature signature : request.getNodeSignatures()) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
nodeSignatures.put(address, signature); | |||
} | |||
} | |||
} | |||
@Override | |||
public TransactionRequest getRequest() { | |||
return request; | |||
} | |||
@Override | |||
public Set<Bytes> getEndpoints() { | |||
return endpointSignatures.keySet(); | |||
} | |||
@Override | |||
public Set<Bytes> getNodes() { | |||
return nodeSignatures.keySet(); | |||
} | |||
@Override | |||
public boolean containsEndpoint(Bytes address) { | |||
return endpointSignatures.containsKey(address); | |||
} | |||
@Override | |||
public boolean containsNode(Bytes address) { | |||
return nodeSignatures.containsKey(address); | |||
} | |||
@Override | |||
public DigitalSignature getEndpointSignature(Bytes address) { | |||
return endpointSignatures.get(address); | |||
} | |||
@Override | |||
public DigitalSignature getNodeSignature(Bytes address) { | |||
return nodeSignatures.get(address); | |||
} | |||
} |
@@ -0,0 +1,115 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Collection; | |||
import java.util.Set; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 交易请求上下文; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionRequestExtension extends TransactionRequest { | |||
// /** | |||
// * 交易请求; | |||
// * | |||
// * @return | |||
// */ | |||
// TransactionRequest getRequest(); | |||
/** | |||
* 签名发起请求的终端用户的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getEndpointAddresses(); | |||
/** | |||
* 签名发起请求的终端用户列表; | |||
* | |||
* @return | |||
*/ | |||
Collection<Credential> getEndpoints(); | |||
/** | |||
* 签名发起请求的节点的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getNodeAddresses(); | |||
/** | |||
* 签名发起请求的节点列表; | |||
* | |||
* @return | |||
*/ | |||
Collection<Credential> getNodes(); | |||
/** | |||
* 请求的终端发起人列表中是否包含指定地址的终端用户; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsEndpoint(Bytes address); | |||
/** | |||
* 请求的经手节点列表中是否包含指定地址的节点; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsNode(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的终端的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getEndpointSignature(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的节点的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getNodeSignature(Bytes address); | |||
public static class Credential { | |||
private final BlockchainIdentity identity; | |||
private final DigitalSignature signature; | |||
Credential(DigitalSignature signature) { | |||
this.identity = new BlockchainIdentityData(signature.getPubKey()); | |||
this.signature = signature; | |||
} | |||
public Bytes getAddress() { | |||
return identity.getAddress(); | |||
} | |||
public PubKey getPubKey() { | |||
return identity.getPubKey(); | |||
} | |||
public BlockchainIdentity getIdentity() { | |||
return identity; | |||
} | |||
public DigitalSignature getSignature() { | |||
return signature; | |||
} | |||
} | |||
} |
@@ -0,0 +1,108 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 交易请求的扩展信息; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TransactionRequestExtensionImpl implements TransactionRequestExtension { | |||
private TransactionRequest request; | |||
private Map<Bytes, Credential> endpointSignatures = new HashMap<>(); | |||
private Map<Bytes, Credential> nodeSignatures = new HashMap<>(); | |||
public TransactionRequestExtensionImpl(TransactionRequest request) { | |||
this.request = request; | |||
resolveSigners(); | |||
} | |||
private void resolveSigners() { | |||
if (request.getEndpointSignatures() != null) { | |||
for (DigitalSignature signature : request.getEndpointSignatures()) { | |||
Credential cred = new Credential(signature); | |||
endpointSignatures.put(cred.getIdentity().getAddress(), cred); | |||
} | |||
} | |||
if (request.getEndpointSignatures() != null) { | |||
for (DigitalSignature signature : request.getNodeSignatures()) { | |||
Credential cred = new Credential(signature); | |||
nodeSignatures.put(cred.getIdentity().getAddress(), cred); | |||
} | |||
} | |||
} | |||
@Override | |||
public Set<Bytes> getEndpointAddresses() { | |||
return endpointSignatures.keySet(); | |||
} | |||
@Override | |||
public Set<Bytes> getNodeAddresses() { | |||
return nodeSignatures.keySet(); | |||
} | |||
@Override | |||
public Collection<Credential> getEndpoints() { | |||
return endpointSignatures.values(); | |||
} | |||
@Override | |||
public Collection<Credential> getNodes() { | |||
return nodeSignatures.values(); | |||
} | |||
@Override | |||
public boolean containsEndpoint(Bytes address) { | |||
return endpointSignatures.containsKey(address); | |||
} | |||
@Override | |||
public boolean containsNode(Bytes address) { | |||
return nodeSignatures.containsKey(address); | |||
} | |||
@Override | |||
public DigitalSignature getEndpointSignature(Bytes address) { | |||
return endpointSignatures.get(address).getSignature(); | |||
} | |||
@Override | |||
public DigitalSignature getNodeSignature(Bytes address) { | |||
return nodeSignatures.get(address).getSignature(); | |||
} | |||
@Override | |||
public HashDigest getHash() { | |||
return request.getHash(); | |||
} | |||
@Override | |||
public DigitalSignature[] getNodeSignatures() { | |||
return request.getNodeSignatures(); | |||
} | |||
@Override | |||
public DigitalSignature[] getEndpointSignatures() { | |||
return request.getEndpointSignatures(); | |||
} | |||
@Override | |||
public TransactionContent getTransactionContent() { | |||
return request.getTransactionContent(); | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Collection; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerPrivilege; | |||
import com.jd.blockchain.ledger.PrivilegeBitset; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionPrivilege; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* {@link UserRolesPrivileges} 表示多角色用户的综合权限; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
class UserRolesPrivileges { | |||
private Bytes userAddress; | |||
private PrivilegeBitset<LedgerPermission> ledgerPrivileges; | |||
private PrivilegeBitset<TransactionPermission> transactionPrivileges; | |||
public UserRolesPrivileges(Bytes userAddress, RolesPolicy policy, Collection<RolePrivileges> privilegesList) { | |||
this.userAddress = userAddress; | |||
LedgerPrivilege[] ledgerPrivileges = privilegesList.stream().map(p -> p.getLedgerPrivilege()) | |||
.toArray(LedgerPrivilege[]::new); | |||
TransactionPrivilege[] transactionPrivileges = privilegesList.stream().map(p -> p.getTransactionPrivilege()) | |||
.toArray(TransactionPrivilege[]::new); | |||
this.ledgerPrivileges = ledgerPrivileges[0].clone(); | |||
this.transactionPrivileges = transactionPrivileges[0].clone(); | |||
if (policy == RolesPolicy.UNION) { | |||
this.ledgerPrivileges.union(ledgerPrivileges, 1, ledgerPrivileges.length - 1); | |||
this.transactionPrivileges.union(transactionPrivileges, 1, transactionPrivileges.length - 1); | |||
} else if (policy == RolesPolicy.INTERSECT) { | |||
this.ledgerPrivileges.intersect(ledgerPrivileges, 1, ledgerPrivileges.length - 1); | |||
this.transactionPrivileges.intersect(transactionPrivileges, 1, transactionPrivileges.length - 1); | |||
} else { | |||
throw new IllegalStateException("Unsupported roles policy[" + policy.toString() + "]!"); | |||
} | |||
} | |||
public Bytes getUserAddress() { | |||
return userAddress; | |||
} | |||
public PrivilegeBitset<LedgerPermission> getLedgerPrivileges() { | |||
return ledgerPrivileges; | |||
} | |||
public PrivilegeBitset<TransactionPermission> getTransactionPrivileges() { | |||
return transactionPrivileges; | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
/** | |||
* 执行直接账本操作的处理类; | |||
* | |||
* @author huanghaiquan | |||
* | |||
* @param <T> | |||
*/ | |||
public abstract class AbstractLedgerOperationHandle<T extends Operation> implements OperationHandle { | |||
static { | |||
DataContractRegistry.register(BytesValue.class); | |||
} | |||
private final Class<T> SUPPORTED_OPERATION_TYPE; | |||
public AbstractLedgerOperationHandle(Class<T> supportedOperationType) { | |||
this.SUPPORTED_OPERATION_TYPE = supportedOperationType; | |||
} | |||
@Override | |||
public final boolean support(Class<?> operationType) { | |||
return SUPPORTED_OPERATION_TYPE.isAssignableFrom(operationType); | |||
} | |||
@Override | |||
public final BytesValue process(Operation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(TransactionPermission.DIRECT_OPERATION, MultiIdsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
@SuppressWarnings("unchecked") | |||
T concretedOp = (T) op; | |||
doProcess(concretedOp, newBlockDataset, requestContext, previousBlockDataset, handleContext, ledgerService); | |||
// 账本操作没有返回值; | |||
return null; | |||
} | |||
/** | |||
* @param op | |||
* @param newBlockDataset | |||
* @param requestContext | |||
* @param previousBlockDataset | |||
* @param handleContext | |||
* @param ledgerService | |||
*/ | |||
protected abstract void doProcess(T op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||
} |
@@ -8,14 +8,18 @@ import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.core.ContractAccount; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
@Service | |||
public abstract class AbtractContractEventHandle implements OperationHandle { | |||
@@ -26,9 +30,22 @@ public abstract class AbtractContractEventHandle implements OperationHandle { | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
public BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(TransactionPermission.CONTRACT_OPERATION, MultiIdsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||
return doProcess(requestContext, contractOP, newBlockDataset, previousBlockDataset, opHandleContext, | |||
ledgerService); | |||
} | |||
private BytesValue doProcess(TransactionRequestExtension request, ContractEventSendOperation contractOP, | |||
LedgerDataset newBlockDataset, LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, | |||
LedgerService ledgerService) { | |||
// 先从账本校验合约的有效性; | |||
// 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; | |||
ContractAccountSet contractSet = previousBlockDataset.getContractAccountset(); | |||
@@ -50,19 +67,17 @@ public abstract class AbtractContractEventHandle implements OperationHandle { | |||
// 创建合约上下文; | |||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | |||
request.getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(request) | |||
.setLedgerContext(ledgerContext); | |||
// 装载合约; | |||
ContractCode contractCode = loadContractCode(contract); | |||
// 处理合约事件; | |||
return contractCode.processEvent(localContractEventContext); | |||
} | |||
protected abstract ContractCode loadContractCode(ContractAccount contract); | |||
protected abstract ContractCode loadContractCode(ContractAccount contract); | |||
} |
@@ -1,41 +1,36 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import org.springframework.stereotype.Service; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
@Service | |||
public class ContractCodeDeployOperationHandle implements OperationHandle { | |||
public class ContractCodeDeployOperationHandle extends AbstractLedgerOperationHandle<ContractCodeDeployOperation> { | |||
public ContractCodeDeployOperationHandle() { | |||
super(ContractCodeDeployOperation.class); | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; | |||
protected void doProcess(ContractCodeDeployOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// TODO: 校验合约代码的正确性; | |||
// TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性; | |||
dataset.getContractAccountset().deploy(contractOP.getContractID().getAddress(), | |||
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); | |||
// TODO: 请求者应该提供合约账户的公钥签名,以确保注册人对注册的地址和公钥具有合法的使用权; | |||
return null; | |||
} | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(LedgerPermission.UPGRADE_CONTRACT, MultiIdsPolicy.AT_LEAST_ONE); | |||
// @Override | |||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// return null; | |||
// } | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return ContractCodeDeployOperation.class.isAssignableFrom(operationType); | |||
// 操作账本; | |||
ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; | |||
newBlockDataset.getContractAccountset().deploy(contractOP.getContractID().getAddress(), | |||
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); | |||
} | |||
} |
@@ -1,32 +1,34 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import org.springframework.stereotype.Service; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountDoesNotExistException; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.utils.Bytes; | |||
@Service | |||
public class DataAccountKVSetOperationHandle implements OperationHandle { | |||
static { | |||
DataContractRegistry.register(BytesValue.class); | |||
public class DataAccountKVSetOperationHandle extends AbstractLedgerOperationHandle<DataAccountKVSetOperation> { | |||
public DataAccountKVSetOperationHandle() { | |||
super(DataAccountKVSetOperation.class); | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; | |||
DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); | |||
protected void doProcess(DataAccountKVSetOperation kvWriteOp, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(LedgerPermission.WRITE_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
DataAccount account = newBlockDataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); | |||
if (account == null) { | |||
throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); | |||
} | |||
@@ -34,17 +36,7 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { | |||
for (KVWriteEntry kvw : writeSet) { | |||
account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); | |||
} | |||
return null; | |||
} | |||
// @Override | |||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// return null; | |||
// } | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return DataAccountKVSetOperation.class.isAssignableFrom(operationType); | |||
} | |||
} |
@@ -1,42 +1,35 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import org.springframework.stereotype.Service; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
@Service | |||
public class DataAccountRegisterOperationHandle implements OperationHandle { | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; | |||
BlockchainIdentity bid = dataAccountRegOp.getAccountID(); | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
//TODO: 校验用户身份; | |||
//TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性; | |||
dataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); | |||
return null; | |||
public class DataAccountRegisterOperationHandle extends AbstractLedgerOperationHandle<DataAccountRegisterOperation> { | |||
public DataAccountRegisterOperationHandle() { | |||
super(DataAccountRegisterOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(DataAccountRegisterOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// TODO: 请求者应该提供数据账户的公钥签名,以更好地确保注册人对该地址和公钥具有合法使用权; | |||
// @Override | |||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// return null; | |||
// } | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(LedgerPermission.REGISTER_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE); | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return DataAccountRegisterOperation.class.isAssignableFrom(operationType); | |||
// 操作账本; | |||
DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; | |||
BlockchainIdentity bid = dataAccountRegOp.getAccountID(); | |||
newBlockDataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); | |||
} | |||
} |
@@ -26,12 +26,4 @@ public class JVMContractEventSendOperationHandle extends AbtractContractEventHan | |||
return contractCode; | |||
} | |||
// @Override | |||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, | |||
// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, | |||
// OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
} |
@@ -1,37 +1,37 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class UserRegisterOperationHandle implements OperationHandle { | |||
public class UserRegisterOperationHandle extends AbstractLedgerOperationHandle<UserRegisterOperation> { | |||
public UserRegisterOperationHandle() { | |||
super(UserRegisterOperation.class); | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
protected void doProcess(UserRegisterOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
UserRegisterOperation userRegOp = (UserRegisterOperation) op; | |||
BlockchainIdentity bid = userRegOp.getUserID(); | |||
Bytes userAddress = bid.getAddress(); | |||
dataset.getUserAccountSet().register(userAddress, bid.getPubKey()); | |||
return null; | |||
} | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return UserRegisterOperation.class.isAssignableFrom(operationType); | |||
newBlockDataset.getUserAccountSet().register(userAddress, bid.getPubKey()); | |||
} | |||
} |
@@ -15,6 +15,7 @@ import org.mockito.Mockito; | |||
import java.util.Random; | |||
import static org.junit.Assert.*; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Matchers.anyLong; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Mockito.*; | |||
@@ -65,15 +66,15 @@ public class ContractInvokingTest { | |||
// 发布指定地址合约 | |||
deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey); | |||
// 创建新区块的交易处理器; | |||
LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | |||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | |||
// 加载合约 | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
@@ -119,16 +120,16 @@ public class ContractInvokingTest { | |||
} | |||
private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager, | |||
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, | |||
BlockchainKeypair contractKey) { | |||
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, BlockchainKeypair contractKey) { | |||
// 创建新区块的交易处理器; | |||
LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | |||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | |||
// 加载合约 | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
@@ -189,4 +190,18 @@ public class ContractInvokingTest { | |||
new Random().nextBytes(chainCode); | |||
return chainCode; | |||
} | |||
private static LedgerSecurityManager getSecurityManager() { | |||
LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); | |||
SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); | |||
when(securityPolicy.isEnableToEndpoints(any(LedgerPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToEndpoints(any(TransactionPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToNodes(any(LedgerPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToNodes(any(TransactionPermission.class), any())).thenReturn(true); | |||
when(securityManager.getSecurityPolicy(any(), any())).thenReturn(securityPolicy); | |||
return securityManager; | |||
} | |||
} |
@@ -0,0 +1,141 @@ | |||
package test.com.jd.blockchain.ledger.core; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.junit.Test; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.CryptoProvider; | |||
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.Privileges; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.UserRoleSettings; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.core.LedgerSecurityManager; | |||
import com.jd.blockchain.ledger.core.LedgerSecurityManagerImpl; | |||
import com.jd.blockchain.ledger.core.MultiIdsPolicy; | |||
import com.jd.blockchain.ledger.core.RolePrivilegeDataset; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.UserRoleDataset; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class LedgerSecurityManagerTest { | |||
private static final String[] SUPPORTED_PROVIDER_NAMES = { ClassicCryptoService.class.getName(), | |||
SMCryptoService.class.getName() }; | |||
private static final CryptoAlgorithm HASH_ALGORITHM = Crypto.getAlgorithm("SHA256"); | |||
private static final CryptoProvider[] SUPPORTED_PROVIDERS = new CryptoProvider[SUPPORTED_PROVIDER_NAMES.length]; | |||
private static final CryptoSetting CRYPTO_SETTINGS; | |||
static { | |||
for (int i = 0; i < SUPPORTED_PROVIDER_NAMES.length; i++) { | |||
SUPPORTED_PROVIDERS[i] = Crypto.getProvider(SUPPORTED_PROVIDER_NAMES[i]); | |||
} | |||
CryptoConfig cryptoConfig = new CryptoConfig(); | |||
cryptoConfig.setAutoVerifyHash(true); | |||
cryptoConfig.setSupportedProviders(SUPPORTED_PROVIDERS); | |||
cryptoConfig.setHashAlgorithm(HASH_ALGORITHM); | |||
CRYPTO_SETTINGS = cryptoConfig; | |||
} | |||
private RolePrivilegeSettings initRoles(MemoryKVStorage testStorage, String[] roles, Privileges[] privilege) { | |||
String prefix = "role-privilege/"; | |||
RolePrivilegeDataset rolePrivilegeDataset = new RolePrivilegeDataset(CRYPTO_SETTINGS, prefix, testStorage, | |||
testStorage); | |||
for (int i = 0; i < roles.length; i++) { | |||
rolePrivilegeDataset.addRolePrivilege(roles[i], privilege[i]); | |||
} | |||
rolePrivilegeDataset.commit(); | |||
return rolePrivilegeDataset; | |||
} | |||
private UserRoleSettings initUserRoless(MemoryKVStorage testStorage, Bytes[] userAddresses, RolesPolicy[] policies, | |||
String[][] roles) { | |||
String prefix = "user-roles/"; | |||
UserRoleDataset userRolesDataset = new UserRoleDataset(CRYPTO_SETTINGS, prefix, testStorage, testStorage); | |||
for (int i = 0; i < userAddresses.length; i++) { | |||
userRolesDataset.addUserRoles(userAddresses[i], policies[i], roles[i]); | |||
} | |||
userRolesDataset.commit(); | |||
return userRolesDataset; | |||
} | |||
@Test | |||
public void testGetSecurityPolicy() { | |||
MemoryKVStorage testStorage = new MemoryKVStorage(); | |||
final BlockchainKeypair kpManager = BlockchainKeyGenerator.getInstance().generate(); | |||
final BlockchainKeypair kpEmployee = BlockchainKeyGenerator.getInstance().generate(); | |||
final BlockchainKeypair kpDevoice = BlockchainKeyGenerator.getInstance().generate(); | |||
final Map<Bytes, BlockchainKeypair> endpoints = new HashMap<>(); | |||
endpoints.put(kpManager.getAddress(), kpManager); | |||
endpoints.put(kpEmployee.getAddress(), kpEmployee); | |||
final Map<Bytes, BlockchainKeypair> nodes = new HashMap<>(); | |||
nodes.put(kpDevoice.getAddress(), kpDevoice); | |||
final String ROLE_ADMIN = "ID_ADMIN"; | |||
final String ROLE_OPERATOR = "OPERATOR"; | |||
final String ROLE_DATA_COLLECTOR = "DATA_COLLECTOR"; | |||
final Privileges PRIVILEGES_ADMIN = Privileges.configure() | |||
.enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) | |||
.enable(TransactionPermission.DIRECT_OPERATION, TransactionPermission.CONTRACT_OPERATION); | |||
final Privileges PRIVILEGES_OPERATOR = Privileges.configure() | |||
.enable(LedgerPermission.WRITE_DATA_ACCOUNT, LedgerPermission.APPROVE_TX) | |||
.enable(TransactionPermission.CONTRACT_OPERATION); | |||
final Privileges PRIVILEGES_DATA_COLLECTOR = Privileges.configure().enable(LedgerPermission.WRITE_DATA_ACCOUNT) | |||
.enable(TransactionPermission.CONTRACT_OPERATION); | |||
RolePrivilegeSettings rolePrivilegeSettings = initRoles(testStorage, | |||
new String[] { ROLE_ADMIN, ROLE_OPERATOR, ROLE_DATA_COLLECTOR }, | |||
new Privileges[] { PRIVILEGES_ADMIN, PRIVILEGES_OPERATOR, PRIVILEGES_DATA_COLLECTOR }); | |||
String[] managerRoles = new String[] { ROLE_ADMIN, ROLE_OPERATOR }; | |||
String[] employeeRoles = new String[] { ROLE_OPERATOR }; | |||
String[] devoiceRoles = new String[] { ROLE_DATA_COLLECTOR }; | |||
UserRoleSettings userRolesSettings = initUserRoless(testStorage, | |||
new Bytes[] { kpManager.getAddress(), kpEmployee.getAddress(), kpDevoice.getAddress() }, | |||
new RolesPolicy[] { RolesPolicy.UNION, RolesPolicy.UNION, RolesPolicy.UNION }, | |||
new String[][] { managerRoles, employeeRoles, devoiceRoles }); | |||
LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl(rolePrivilegeSettings, userRolesSettings); | |||
SecurityPolicy policy = securityManager.getSecurityPolicy(endpoints.keySet(), nodes.keySet()); | |||
assertTrue(policy.isEnableToEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.AT_LEAST_ONE)); | |||
assertTrue(policy.isEnableToEndpoints(LedgerPermission.REGISTER_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE)); | |||
assertTrue(policy.isEnableToEndpoints(LedgerPermission.WRITE_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE)); | |||
assertTrue(policy.isEnableToEndpoints(LedgerPermission.APPROVE_TX, MultiIdsPolicy.AT_LEAST_ONE)); | |||
assertFalse(policy.isEnableToEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.ALL)); | |||
assertFalse(policy.isEnableToEndpoints(LedgerPermission.AUTHORIZE_ROLES, MultiIdsPolicy.AT_LEAST_ONE)); | |||
} | |||
} |
@@ -5,8 +5,11 @@ import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.when; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
@@ -17,10 +20,12 @@ import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.EndpointRequest; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionContentBody; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
@@ -31,9 +36,11 @@ import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerManager; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.ledger.core.LedgerSecurityManager; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; | |||
import com.jd.blockchain.ledger.core.OperationHandleRegisteration; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionBatchProcessor; | |||
import com.jd.blockchain.ledger.core.UserAccount; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
@@ -85,8 +92,9 @@ public class TransactionBatchProcessorTest { | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
// 注册新用户; | |||
BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); | |||
@@ -108,6 +116,20 @@ public class TransactionBatchProcessorTest { | |||
assertEquals(TransactionState.SUCCESS, txResp.getExecutionState()); | |||
} | |||
private static LedgerSecurityManager getSecurityManager() { | |||
LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); | |||
SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); | |||
when(securityPolicy.isEnableToEndpoints(any(LedgerPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToEndpoints(any(TransactionPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToNodes(any(LedgerPermission.class), any())).thenReturn(true); | |||
when(securityPolicy.isEnableToNodes(any(TransactionPermission.class), any())).thenReturn(true); | |||
when(securityManager.getSecurityPolicy(any(), any())).thenReturn(securityPolicy); | |||
return securityManager; | |||
} | |||
@Test | |||
public void testMultiTxsProcess() { | |||
final MemoryKVStorage STORAGE = new MemoryKVStorage(); | |||
@@ -130,8 +152,9 @@ public class TransactionBatchProcessorTest { | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
// 注册新用户; | |||
BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); | |||
@@ -187,8 +210,9 @@ public class TransactionBatchProcessorTest { | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
// 注册新用户; | |||
BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); | |||
@@ -267,8 +291,9 @@ public class TransactionBatchProcessorTest { | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||
opReg, ledgerManager); | |||
LedgerSecurityManager securityManager = getSecurityManager(); | |||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, | |||
previousBlockDataset, opReg, ledgerManager); | |||
BlockchainKeypair dataAccountKeypair = BlockchainKeyGenerator.getInstance().generate(); | |||
TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_DataAccountReg(dataAccountKeypair, | |||
@@ -293,7 +318,8 @@ public class TransactionBatchProcessorTest { | |||
newBlockEditor = ledgerRepo.createNextBlock(); | |||
previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); | |||
txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); | |||
txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, previousBlockDataset, opReg, | |||
ledgerManager); | |||
txbatchProcessor.schedule(txreq1); | |||
txbatchProcessor.schedule(txreq2); | |||
@@ -316,7 +342,7 @@ public class TransactionBatchProcessorTest { | |||
assertNotNull(v1_1); | |||
assertNotNull(v2); | |||
assertNotNull(v3); | |||
assertEquals("V-1-1", v1_0.getValue().toUTF8String()); | |||
assertEquals("V-1-2", v1_1.getValue().toUTF8String()); | |||
assertEquals("V-2-1", v2.getValue().toUTF8String()); | |||
@@ -332,7 +358,8 @@ public class TransactionBatchProcessorTest { | |||
newBlockEditor = ledgerRepo.createNextBlock(); | |||
previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); | |||
txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); | |||
txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, previousBlockDataset, opReg, | |||
ledgerManager); | |||
txbatchProcessor.schedule(txreq5); | |||
txbatchProcessor.schedule(txreq6); | |||
@@ -343,11 +370,13 @@ public class TransactionBatchProcessorTest { | |||
BytesValue v1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1"); | |||
v3 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K3"); | |||
long k1_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K1"); | |||
long k1_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()) | |||
.getDataVersion("K1"); | |||
assertEquals(1, k1_version); | |||
long k3_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K3"); | |||
long k3_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()) | |||
.getDataVersion("K3"); | |||
assertEquals(1, k3_version); | |||
assertNotNull(v1); | |||
assertNotNull(v3); | |||
assertEquals("V-1-2", v1.getValue().toUTF8String()); | |||
@@ -1,58 +0,0 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.util.BitSet; | |||
import com.jd.blockchain.utils.io.BytesSerializable; | |||
/** | |||
* LedgerPrivilege 账本特权是授权给特定角色的权限代码序列; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public abstract class AbstractPrivilege<E extends Enum<?>> implements Privilege<E>, BytesSerializable { | |||
private BitSet permissionBits; | |||
public AbstractPrivilege() { | |||
permissionBits = new BitSet(); | |||
} | |||
public AbstractPrivilege(byte[] codeBytes) { | |||
permissionBits = BitSet.valueOf(codeBytes); | |||
} | |||
public boolean isEnable(E permission) { | |||
return permissionBits.get(getCodeIndex(permission)); | |||
} | |||
public void enable(E permission) { | |||
permissionBits.set(getCodeIndex(permission)); | |||
} | |||
public void disable(E permission) { | |||
permissionBits.clear(getCodeIndex(permission)); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public void enable(E... permissions) { | |||
for (E p : permissions) { | |||
permissionBits.set(getCodeIndex(p)); | |||
} | |||
} | |||
@SuppressWarnings("unchecked") | |||
public void disable(E... permissions) { | |||
for (E p : permissions) { | |||
permissionBits.clear(getCodeIndex(p)); | |||
} | |||
} | |||
protected abstract int getCodeIndex(E permission); | |||
@Override | |||
public byte[] toBytes() { | |||
return permissionBits.toByteArray(); | |||
} | |||
} |
@@ -6,18 +6,24 @@ package com.jd.blockchain.ledger; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerPrivilege extends AbstractPrivilege<LedgerPermission> { | |||
public class LedgerPrivilege extends PrivilegeBitset<LedgerPermission> { | |||
private static final CodeIndexer<LedgerPermission> CODE_INDEXER = new LedgerPermissionCodeIndexer(); | |||
public LedgerPrivilege() { | |||
super(CODE_INDEXER); | |||
} | |||
public LedgerPrivilege(byte[] codeBytes) { | |||
super(codeBytes); | |||
super(codeBytes, CODE_INDEXER); | |||
} | |||
@Override | |||
protected int getCodeIndex(LedgerPermission permission) { | |||
return permission.CODE & 0xFF; | |||
} | |||
private static class LedgerPermissionCodeIndexer implements CodeIndexer<LedgerPermission> { | |||
@Override | |||
public int getCodeIndex(LedgerPermission permission) { | |||
return permission.CODE & 0xFF; | |||
} | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
package com.jd.blockchain.ledger; | |||
public class LedgerSecurityException extends RuntimeException { | |||
private static final long serialVersionUID = -4090881296855827888L; | |||
public LedgerSecurityException(String message) { | |||
super(message); | |||
} | |||
public LedgerSecurityException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
package com.jd.blockchain.ledger; | |||
public class ParticipantDoesNotExistException extends LedgerException { | |||
private static final long serialVersionUID = 397450363050148898L; | |||
public ParticipantDoesNotExistException(String message) { | |||
super(message); | |||
} | |||
public ParticipantDoesNotExistException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -0,0 +1,121 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.util.BitSet; | |||
import com.jd.blockchain.utils.io.BytesSerializable; | |||
/** | |||
* PrivilegeBitset 定义了用位表示的权限码; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class PrivilegeBitset<E extends Enum<?>> implements Privilege<E>, BytesSerializable { | |||
private BitSet permissionBits; | |||
private CodeIndexer<E> codeIndexer; | |||
public PrivilegeBitset(CodeIndexer<E> codeIndexer) { | |||
this(new BitSet(), codeIndexer); | |||
} | |||
public PrivilegeBitset(byte[] codeBytes, CodeIndexer<E> codeIndexer) { | |||
this(BitSet.valueOf(codeBytes), codeIndexer); | |||
} | |||
private PrivilegeBitset(BitSet bits, CodeIndexer<E> codeIndexer) { | |||
this.permissionBits = bits; | |||
this.codeIndexer = codeIndexer; | |||
} | |||
public boolean isEnable(E permission) { | |||
return permissionBits.get(codeIndexer.getCodeIndex(permission)); | |||
} | |||
public void enable(E permission) { | |||
permissionBits.set(codeIndexer.getCodeIndex(permission)); | |||
} | |||
public void disable(E permission) { | |||
permissionBits.clear(codeIndexer.getCodeIndex(permission)); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public void enable(E... permissions) { | |||
for (E p : permissions) { | |||
permissionBits.set(codeIndexer.getCodeIndex(p)); | |||
} | |||
} | |||
@SuppressWarnings("unchecked") | |||
public void disable(E... permissions) { | |||
for (E p : permissions) { | |||
permissionBits.clear(codeIndexer.getCodeIndex(p)); | |||
} | |||
} | |||
@Override | |||
public byte[] toBytes() { | |||
return permissionBits.toByteArray(); | |||
} | |||
/** | |||
* 把指定的权限合并到当前的权限中; <br> | |||
* | |||
* @param privileges | |||
* @return | |||
*/ | |||
public Privilege<E> union(PrivilegeBitset<E>... privileges) { | |||
return union(privileges, 0, privileges.length); | |||
} | |||
/** | |||
* 把指定的权限合并到当前的权限中; <br> | |||
* @param privileges | |||
* @param offset | |||
* @param count | |||
* @return | |||
*/ | |||
public Privilege<E> union(PrivilegeBitset<E>[] privileges, int offset, int count) { | |||
BitSet bits = this.permissionBits; | |||
for (int i = 0; i < count; i++) { | |||
bits.or(privileges[i + offset].permissionBits); | |||
} | |||
return this; | |||
} | |||
/** | |||
* 保留当前的权限与指定权限的共同生效的部分,同时清除其它的权限位; <br> | |||
* | |||
* @param privileges | |||
* @return | |||
*/ | |||
public Privilege<E> intersect(PrivilegeBitset<E>... privileges) { | |||
return intersect(privileges, 0, privileges.length); | |||
} | |||
/** | |||
* 保留当前的权限与指定权限的共同生效的部分,同时清除其它的权限位; <br> | |||
* | |||
* @param privileges | |||
* @param offset | |||
* @param count | |||
* @return | |||
*/ | |||
public Privilege<E> intersect(PrivilegeBitset<E>[] privileges, int offset, int count) { | |||
BitSet bits = this.permissionBits; | |||
for (int i = 0; i < count; i++) { | |||
bits.and(privileges[i + offset].permissionBits); | |||
} | |||
return this; | |||
} | |||
public PrivilegeBitset<E> clone() { | |||
return new PrivilegeBitset<E>((BitSet) permissionBits.clone(), codeIndexer); | |||
} | |||
static interface CodeIndexer<E extends Enum<?>> { | |||
int getCodeIndex(E permission); | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
package com.jd.blockchain.ledger; | |||
public class Privileges implements PrivilegeSet { | |||
private LedgerPrivilege ledgerPrivilege; | |||
private TransactionPrivilege txPrivilege; | |||
protected Privileges() { | |||
this.ledgerPrivilege = new LedgerPrivilege(); | |||
this.txPrivilege = new TransactionPrivilege(); | |||
} | |||
protected Privileges(PrivilegeSet privilege) { | |||
this.ledgerPrivilege = privilege.getLedgerPrivilege(); | |||
this.txPrivilege = privilege.getTransactionPrivilege(); | |||
} | |||
protected Privileges(LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | |||
this.ledgerPrivilege = ledgerPrivilege; | |||
this.txPrivilege = txPrivilege; | |||
} | |||
@Override | |||
public LedgerPrivilege getLedgerPrivilege() { | |||
return ledgerPrivilege; | |||
} | |||
public void setLedgerPrivilege(LedgerPrivilege ledgerPrivilege) { | |||
this.ledgerPrivilege = ledgerPrivilege; | |||
} | |||
@Override | |||
public TransactionPrivilege getTransactionPrivilege() { | |||
return txPrivilege; | |||
} | |||
public void setTransactionPrivilege(TransactionPrivilege txPrivilege) { | |||
this.txPrivilege = txPrivilege; | |||
} | |||
public static Privileges configure() { | |||
return new Privileges(); | |||
} | |||
public Privileges enable(LedgerPermission...ledgerPermissions) { | |||
this.ledgerPrivilege.enable(ledgerPermissions); | |||
return this; | |||
} | |||
public Privileges disable(LedgerPermission...ledgerPermissions) { | |||
this.ledgerPrivilege.disable(ledgerPermissions); | |||
return this; | |||
} | |||
public Privileges enable(TransactionPermission...transactionPermissions) { | |||
this.txPrivilege.enable(transactionPermissions); | |||
return this; | |||
} | |||
public Privileges disable(TransactionPermission...transactionPermissions) { | |||
this.txPrivilege.disable(transactionPermissions); | |||
return this; | |||
} | |||
} |
@@ -8,6 +8,17 @@ public interface RolePrivilegeSettings { | |||
public static final int MAX_ROLE_NAME_LENGTH = 20; | |||
long getRoleCount(); | |||
/** | |||
* 加入新的角色授权; <br> | |||
* | |||
* 如果指定的角色已经存在,则引发 {@link LedgerException} 异常; | |||
* | |||
* @param roleName 角色名称;不能超过 {@link #MAX_ROLE_NAME_LENGTH} 个 Unicode 字符; | |||
* @param ledgerPrivilege | |||
* @param txPrivilege | |||
*/ | |||
long addRolePrivilege(String roleName, Privileges privileges); | |||
/** | |||
* 加入新的角色授权; <br> | |||
@@ -6,35 +6,28 @@ package com.jd.blockchain.ledger; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class RolePrivileges implements PrivilegeSet { | |||
public class RolePrivileges extends Privileges { | |||
private String roleName; | |||
private long version; | |||
private LedgerPrivilege ledgerPrivilege; | |||
private TransactionPrivilege txPrivilege; | |||
public RolePrivileges(String roleName, long version) { | |||
this.roleName = roleName; | |||
this.version = version; | |||
this.ledgerPrivilege = new LedgerPrivilege(); | |||
this.txPrivilege = new TransactionPrivilege(); | |||
} | |||
public RolePrivileges(String roleName, long version, PrivilegeSet privilege) { | |||
super(privilege); | |||
this.roleName = roleName; | |||
this.version = version; | |||
this.ledgerPrivilege = privilege.getLedgerPrivilege(); | |||
this.txPrivilege = privilege.getTransactionPrivilege(); | |||
} | |||
public RolePrivileges(String roleName, long version, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | |||
public RolePrivileges(String roleName, long version, LedgerPrivilege ledgerPrivilege, | |||
TransactionPrivilege txPrivilege) { | |||
super(ledgerPrivilege, txPrivilege); | |||
this.roleName = roleName; | |||
this.version = version; | |||
this.ledgerPrivilege = ledgerPrivilege; | |||
this.txPrivilege = txPrivilege; | |||
} | |||
public String getRoleName() { | |||
@@ -45,22 +38,4 @@ public class RolePrivileges implements PrivilegeSet { | |||
return version; | |||
} | |||
@Override | |||
public LedgerPrivilege getLedgerPrivilege() { | |||
return ledgerPrivilege; | |||
} | |||
public void setLedgerPrivilege(LedgerPrivilege ledgerPrivilege) { | |||
this.ledgerPrivilege = ledgerPrivilege; | |||
} | |||
@Override | |||
public TransactionPrivilege getTransactionPrivilege() { | |||
return txPrivilege; | |||
} | |||
public void setTransactionPrivilege(TransactionPrivilege txPrivilege) { | |||
this.txPrivilege = txPrivilege; | |||
} | |||
} |
@@ -1,17 +1,23 @@ | |||
package com.jd.blockchain.ledger; | |||
public class TransactionPrivilege extends AbstractPrivilege<TransactionPermission> { | |||
public class TransactionPrivilege extends PrivilegeBitset<TransactionPermission> { | |||
private static final CodeIndexer<TransactionPermission> CODE_INDEXER = new TransactionPermissionCodeIndexer(); | |||
public TransactionPrivilege() { | |||
super(CODE_INDEXER); | |||
} | |||
public TransactionPrivilege(byte[] codeBytes) { | |||
super(codeBytes); | |||
super(codeBytes, CODE_INDEXER); | |||
} | |||
@Override | |||
protected int getCodeIndex(TransactionPermission permission) { | |||
return permission.CODE & 0xFF; | |||
} | |||
private static class TransactionPermissionCodeIndexer implements CodeIndexer<TransactionPermission> { | |||
@Override | |||
public int getCodeIndex(TransactionPermission permission) { | |||
return permission.CODE & 0xFF; | |||
} | |||
} | |||
} |
@@ -39,6 +39,16 @@ public enum TransactionState { | |||
*/ | |||
CONTRACT_DOES_NOT_EXIST((byte) 0x04), | |||
/** | |||
* 参与方不存在; | |||
*/ | |||
PARTICIPANT_DOES_NOT_EXIST((byte) 0x05), | |||
/** | |||
* 被安全策略拒绝; | |||
*/ | |||
REJECTED_BY_SECURITY_POLICY((byte) 0x10), | |||
/** | |||
* 由于在错误的账本上执行交易而被丢弃; | |||
*/ | |||
@@ -37,6 +37,7 @@ import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.Operation; | |||
@@ -44,6 +45,7 @@ import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionContentBody; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
@@ -56,6 +58,8 @@ import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerManager; | |||
import com.jd.blockchain.ledger.core.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.ledger.core.LedgerSecurityManager; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionBatchProcessor; | |||
import com.jd.blockchain.mocker.config.MockerConstant; | |||
import com.jd.blockchain.mocker.config.PresetAnswerPrompter; | |||
@@ -121,7 +125,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||
DataContractRegistry.register(ActionResponse.class); | |||
DataContractRegistry.register(ClientIdentifications.class); | |||
DataContractRegistry.register(ClientIdentification.class); | |||
// DataContractRegistry.register(LedgerAdminInfo.class); | |||
ByteArrayObjectUtil.init(); | |||
@@ -273,7 +277,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||
public LedgerInfo getLedger(HashDigest ledgerHash) { | |||
return queryService.getLedger(ledgerHash); | |||
} | |||
@Override | |||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||
return queryService.getLedgerAdminInfo(ledgerHash); | |||
@@ -410,7 +414,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||
} | |||
@Override | |||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||
return queryService.getContract(ledgerHash, address); | |||
} | |||
@@ -443,8 +447,8 @@ public class MockerNodeContext implements BlockchainQueryService { | |||
LedgerEditor newEditor = ledgerRepository.createNextBlock(); | |||
LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); | |||
LedgerDataset previousDataSet = ledgerRepository.getDataSet(latestBlock); | |||
TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler, | |||
ledgerManager); | |||
TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, | |||
previousDataSet, opHandler, ledgerManager); | |||
TransactionResponse txResp = txProc.schedule(txRequest); | |||
TransactionBatchResultHandle handle = txProc.prepare(); | |||
handle.commit(); | |||
@@ -16,7 +16,7 @@ import com.jd.blockchain.ledger.core.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.ledger.core.handles.ContractLedgerContext; | |||
import com.jd.blockchain.mocker.proxy.ExecutorProxy; | |||
@@ -29,7 +29,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||
private HashDigest ledgerHash; | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, | |||
public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestExtension requestContext, | |||
LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||