@@ -290,6 +290,10 @@ public class LedgerAdminDataset implements Transactional, LedgerAdminInfo { | |||||
return participants.getParticipants(); | return participants.getParticipants(); | ||||
} | } | ||||
ParticipantDataset getParticipantDataset() { | |||||
return participants; | |||||
} | |||||
/** | /** | ||||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | * 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | ||||
* | * | ||||
@@ -30,7 +30,7 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class LedgerRepositoryImpl implements LedgerRepository { | |||||
class LedgerRepositoryImpl implements LedgerRepository { | |||||
private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); | 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) { | private LedgerDataset innerGetLedgerDataset(LedgerBlock block) { | ||||
LedgerAdminDataset adminDataset = createAdminDataset(block); | LedgerAdminDataset adminDataset = createAdminDataset(block); | ||||
CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); | CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); | ||||
UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); | UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); | ||||
DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); | DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); | ||||
ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); | ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); | ||||
@@ -2,37 +2,12 @@ package com.jd.blockchain.ledger.core; | |||||
import java.util.Set; | 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); | 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 | @Override | ||||
public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | ||||
// if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { | // if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { | ||||
@@ -250,15 +227,6 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||||
TransactionState.IGNORED_BY_WRONG_LEDGER); | 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) { | if (currentTxCtx != null) { | ||||
throw new IllegalStateException( | throw new IllegalStateException( | ||||
"Unable to open another new transaction before the current transaction is completed! --[TxHash=" | "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.BytesValue; | ||||
import com.jd.blockchain.ledger.Operation; | import com.jd.blockchain.ledger.Operation; | ||||
public interface OperationHandle { | 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); | 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; | import com.jd.blockchain.ledger.Operation; | ||||
/** | |||||
* 在交易处理过程中,提供对多种交易操作处理器互相调用的机制; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public interface OperationHandleContext { | public interface OperationHandleContext { | ||||
void handle(Operation operation); | void handle(Operation operation); | ||||
} | } |
@@ -77,6 +77,12 @@ public class ParticipantDataset implements Transactional, MerkleProvable { | |||||
return address; | 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.LedgerPermission; | ||||
import com.jd.blockchain.ledger.LedgerPrivilege; | import com.jd.blockchain.ledger.LedgerPrivilege; | ||||
import com.jd.blockchain.ledger.PrivilegeSet; | import com.jd.blockchain.ledger.PrivilegeSet; | ||||
import com.jd.blockchain.ledger.Privileges; | |||||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | import com.jd.blockchain.ledger.RolePrivilegeSettings; | ||||
import com.jd.blockchain.ledger.RolePrivileges; | import com.jd.blockchain.ledger.RolePrivileges; | ||||
import com.jd.blockchain.ledger.TransactionPermission; | import com.jd.blockchain.ledger.TransactionPermission; | ||||
@@ -61,9 +62,11 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role | |||||
return dataset.getDataCount(); | return dataset.getDataCount(); | ||||
} | } | ||||
/** | |||||
* | |||||
*/ | |||||
@Override | |||||
public long addRolePrivilege(String roleName, Privileges privileges) { | |||||
return addRolePrivilege(roleName, privileges.getLedgerPrivilege(), privileges.getTransactionPrivilege()); | |||||
} | |||||
@Override | @Override | ||||
public long addRolePrivilege(String roleName, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | public long addRolePrivilege(String roleName, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | ||||
RolePrivileges roleAuth = new RolePrivileges(roleName, -1, ledgerPrivilege, 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; | package com.jd.blockchain.ledger.core; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collection; | |||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | 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.IllegalTransactionException; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerException; | 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.Operation; | ||||
import com.jd.blockchain.ledger.OperationResult; | import com.jd.blockchain.ledger.OperationResult; | ||||
import com.jd.blockchain.ledger.OperationResultData; | 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.TransactionRequest; | ||||
import com.jd.blockchain.ledger.TransactionResponse; | import com.jd.blockchain.ledger.TransactionResponse; | ||||
import com.jd.blockchain.ledger.TransactionRollbackException; | import com.jd.blockchain.ledger.TransactionRollbackException; | ||||
import com.jd.blockchain.ledger.TransactionState; | import com.jd.blockchain.ledger.TransactionState; | ||||
import com.jd.blockchain.ledger.UserDoesNotExistException; | 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.TransactionBatchProcess; | ||||
import com.jd.blockchain.service.TransactionBatchResult; | import com.jd.blockchain.service.TransactionBatchResult; | ||||
import com.jd.blockchain.service.TransactionBatchResultHandle; | 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.transaction.TxResponseMessage; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
public class TransactionBatchProcessor implements TransactionBatchProcess { | public class TransactionBatchProcessor implements TransactionBatchProcess { | ||||
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); | private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); | ||||
private LedgerSecurityManager securityManager; | |||||
private LedgerService ledgerService; | private LedgerService ledgerService; | ||||
private LedgerEditor newBlockEditor; | private LedgerEditor newBlockEditor; | ||||
@@ -55,8 +64,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | ||||
* @param opHandles 操作处理对象注册表; | * @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.newBlockEditor = newBlockEditor; | ||||
this.previousBlockDataset = previousBlockDataset; | this.previousBlockDataset = previousBlockDataset; | ||||
this.opHandles = opHandles; | this.opHandles = opHandles; | ||||
@@ -76,12 +86,26 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
try { | try { | ||||
LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", | LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", | ||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | 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); | LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); | ||||
// 处理交易; | // 处理交易; | ||||
resp = handleTx(request, txCtx); | |||||
resp = handleTx(reqExt, txCtx); | |||||
LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", | LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", | ||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | 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", | "Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | ||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
e.getMessage()), e); | e.getMessage()), e); | ||||
} catch (BlockRollbackException e) { | } catch (BlockRollbackException e) { | ||||
// 抛弃发生处理异常的交易请求; | |||||
// resp = discard(request, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); | |||||
// 发生区块级别的处理异常,向上重新抛出异常进行处理,整个区块可能被丢弃; | |||||
LOGGER.error(String.format( | LOGGER.error(String.format( | ||||
"Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | "Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | ||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
@@ -110,12 +133,86 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
e.getMessage()), e); | e.getMessage()), e); | ||||
} finally { | |||||
// 清空交易的用户安全策略; | |||||
SecurityContext.removeContextUsersPolicy(); | |||||
} | } | ||||
responseList.add(resp); | responseList.add(resp); | ||||
return 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> | * 处理交易;<br> | ||||
* | * | ||||
@@ -125,23 +222,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
* @param txCtx | * @param txCtx | ||||
* @return | * @return | ||||
*/ | */ | ||||
private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) { | |||||
private TransactionResponse handleTx(TransactionRequestExtension request, LedgerTransactionContext txCtx) { | |||||
TransactionState result; | TransactionState result; | ||||
List<OperationResult> operationResults = new ArrayList<>(); | List<OperationResult> operationResults = new ArrayList<>(); | ||||
try { | try { | ||||
LedgerDataset dataset = txCtx.getDataset(); | 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(); | 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 | // assert; Instance of operation are one of User related operations or | ||||
// DataAccount related operations; | // DataAccount related operations; | ||||
OperationHandle hdl = opHandles.getHandle(operation.getClass()); | OperationHandle hdl = opHandles.getHandle(operation.getClass()); | ||||
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); | |||||
hdl.process(operation, dataset, request, previousBlockDataset, this, ledgerService); | |||||
} | } | ||||
}; | }; | ||||
OperationHandle opHandle; | OperationHandle opHandle; | ||||
int opIndex = 0; | int opIndex = 0; | ||||
for (Operation op : ops) { | for (Operation op : ops) { | ||||
opHandle = opHandles.getHandle(op.getClass()); | opHandle = opHandles.getHandle(op.getClass()); | ||||
BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, | |||||
BytesValue opResult = opHandle.process(op, dataset, request, previousBlockDataset, handleContext, | |||||
ledgerService); | ledgerService); | ||||
if (opResult != null) { | if (opResult != null) { | ||||
operationResults.add(new OperationResultData(opIndex, opResult)); | operationResults.add(new OperationResultData(opIndex, opResult)); | ||||
@@ -177,6 +262,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
e.getMessage()), e); | e.getMessage()), e); | ||||
} catch (BlockRollbackException e) { | } catch (BlockRollbackException e) { | ||||
// 回滚整个区块; | |||||
result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; | result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; | ||||
txCtx.rollback(); | txCtx.rollback(); | ||||
LOGGER.error( | LOGGER.error( | ||||
@@ -195,17 +281,27 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||||
result = TransactionState.USER_DOES_NOT_EXIST; | result = TransactionState.USER_DOES_NOT_EXIST; | ||||
} else if (e instanceof ContractDoesNotExistException) { | } else if (e instanceof ContractDoesNotExistException) { | ||||
result = TransactionState.CONTRACT_DOES_NOT_EXIST; | result = TransactionState.CONTRACT_DOES_NOT_EXIST; | ||||
} else if (e instanceof ParticipantDoesNotExistException) { | |||||
result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; | |||||
} | } | ||||
txCtx.discardAndCommit(result, operationResults); | txCtx.discardAndCommit(result, operationResults); | ||||
LOGGER.error(String.format( | 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(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
e.getMessage()), e); | e.getMessage()), e); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
result = TransactionState.SYSTEM_ERROR; | result = TransactionState.SYSTEM_ERROR; | ||||
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); | txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); | ||||
LOGGER.error(String.format( | 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(), | newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | ||||
e.getMessage()), e); | e.getMessage()), e); | ||||
} | } | ||||
@@ -41,8 +41,12 @@ public class TransactionEngineImpl implements TransactionEngine { | |||||
LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | ||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | ||||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(ledgerBlock); | 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); | batchs.put(ledgerHash, batch); | ||||
return 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) { | LedgerService ledgerService, long blockHeight) { | ||||
super(newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||||
super(securityManager, newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||||
this.ledgerHash = ledgerHash; | this.ledgerHash = ledgerHash; | ||||
this.blockHeight = blockHeight; | 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.ContractEventSendOperation; | ||||
import com.jd.blockchain.ledger.LedgerException; | import com.jd.blockchain.ledger.LedgerException; | ||||
import com.jd.blockchain.ledger.Operation; | 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.ContractAccount; | ||||
import com.jd.blockchain.ledger.core.ContractAccountSet; | import com.jd.blockchain.ledger.core.ContractAccountSet; | ||||
import com.jd.blockchain.ledger.core.LedgerDataset; | import com.jd.blockchain.ledger.core.LedgerDataset; | ||||
import com.jd.blockchain.ledger.core.LedgerQueryService; | import com.jd.blockchain.ledger.core.LedgerQueryService; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | 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.OperationHandle; | ||||
import com.jd.blockchain.ledger.core.OperationHandleContext; | 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 | @Service | ||||
public abstract class AbtractContractEventHandle implements OperationHandle { | public abstract class AbtractContractEventHandle implements OperationHandle { | ||||
@@ -26,9 +30,22 @@ public abstract class AbtractContractEventHandle implements OperationHandle { | |||||
} | } | ||||
@Override | @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) { | LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | ||||
// 权限校验; | |||||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||||
securityPolicy.checkEndpoints(TransactionPermission.CONTRACT_OPERATION, MultiIdsPolicy.AT_LEAST_ONE); | |||||
// 操作账本; | |||||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | 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(); | ContractAccountSet contractSet = previousBlockDataset.getContractAccountset(); | ||||
@@ -50,19 +67,17 @@ public abstract class AbtractContractEventHandle implements OperationHandle { | |||||
// 创建合约上下文; | // 创建合约上下文; | ||||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | 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); | .setLedgerContext(ledgerContext); | ||||
// 装载合约; | // 装载合约; | ||||
ContractCode contractCode = loadContractCode(contract); | ContractCode contractCode = loadContractCode(contract); | ||||
// 处理合约事件; | // 处理合约事件; | ||||
return contractCode.processEvent(localContractEventContext); | 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; | 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.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.LedgerDataset; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | 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.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 | @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: 校验合约代码的正确性; | ||||
// 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; | 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.DataAccountDoesNotExistException; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | import com.jd.blockchain.ledger.DataAccountKVSetOperation; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; | 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.DataAccount; | ||||
import com.jd.blockchain.ledger.core.LedgerDataset; | import com.jd.blockchain.ledger.core.LedgerDataset; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | 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.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; | 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 | @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) { | if (account == null) { | ||||
throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); | throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); | ||||
} | } | ||||
@@ -34,17 +36,7 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { | |||||
for (KVWriteEntry kvw : writeSet) { | for (KVWriteEntry kvw : writeSet) { | ||||
account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); | 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; | package com.jd.blockchain.ledger.core.handles; | ||||
import org.springframework.stereotype.Service; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | 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.LedgerDataset; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | 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.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; | 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; | package com.jd.blockchain.ledger.core.handles; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | 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.UserRegisterOperation; | ||||
import com.jd.blockchain.ledger.core.LedgerDataset; | import com.jd.blockchain.ledger.core.LedgerDataset; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | 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.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; | import com.jd.blockchain.utils.Bytes; | ||||
public class UserRegisterOperationHandle implements OperationHandle { | |||||
public class UserRegisterOperationHandle extends AbstractLedgerOperationHandle<UserRegisterOperation> { | |||||
public UserRegisterOperationHandle() { | |||||
super(UserRegisterOperation.class); | |||||
} | |||||
@Override | @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; | UserRegisterOperation userRegOp = (UserRegisterOperation) op; | ||||
BlockchainIdentity bid = userRegOp.getUserID(); | BlockchainIdentity bid = userRegOp.getUserID(); | ||||
Bytes userAddress = bid.getAddress(); | 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 java.util.Random; | ||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
import static org.mockito.Matchers.any; | |||||
import static org.mockito.Matchers.anyLong; | import static org.mockito.Matchers.anyLong; | ||||
import static org.mockito.Matchers.anyString; | import static org.mockito.Matchers.anyString; | ||||
import static org.mockito.Mockito.*; | import static org.mockito.Mockito.*; | ||||
@@ -65,15 +66,15 @@ public class ContractInvokingTest { | |||||
// 发布指定地址合约 | // 发布指定地址合约 | ||||
deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey); | deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey); | ||||
// 创建新区块的交易处理器; | // 创建新区块的交易处理器; | ||||
LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | ||||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | ||||
// 加载合约 | // 加载合约 | ||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | 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); | TxBuilder txBuilder = new TxBuilder(ledgerHash); | ||||
@@ -119,16 +120,16 @@ public class ContractInvokingTest { | |||||
} | } | ||||
private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager, | private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager, | ||||
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, | |||||
BlockchainKeypair contractKey) { | |||||
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, BlockchainKeypair contractKey) { | |||||
// 创建新区块的交易处理器; | // 创建新区块的交易处理器; | ||||
LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | ||||
LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); | ||||
// 加载合约 | // 加载合约 | ||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | 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); | TxBuilder txBuilder = new TxBuilder(ledgerHash); | ||||
@@ -189,4 +190,18 @@ public class ContractInvokingTest { | |||||
new Random().nextBytes(chainCode); | new Random().nextBytes(chainCode); | ||||
return 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.assertNotNull; | ||||
import static org.junit.Assert.assertNull; | import static org.junit.Assert.assertNull; | ||||
import static org.junit.Assert.assertTrue; | import static org.junit.Assert.assertTrue; | ||||
import static org.mockito.Matchers.any; | |||||
import static org.mockito.Mockito.when; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.mockito.Mockito; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
import com.jd.blockchain.crypto.HashDigest; | 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.EndpointRequest; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInitSetting; | import com.jd.blockchain.ledger.LedgerInitSetting; | ||||
import com.jd.blockchain.ledger.LedgerPermission; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
import com.jd.blockchain.ledger.NodeRequest; | import com.jd.blockchain.ledger.NodeRequest; | ||||
import com.jd.blockchain.ledger.TransactionContent; | import com.jd.blockchain.ledger.TransactionContent; | ||||
import com.jd.blockchain.ledger.TransactionContentBody; | import com.jd.blockchain.ledger.TransactionContentBody; | ||||
import com.jd.blockchain.ledger.TransactionPermission; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | import com.jd.blockchain.ledger.TransactionRequest; | ||||
import com.jd.blockchain.ledger.TransactionResponse; | import com.jd.blockchain.ledger.TransactionResponse; | ||||
import com.jd.blockchain.ledger.TransactionState; | 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.LedgerEditor; | ||||
import com.jd.blockchain.ledger.core.LedgerManager; | import com.jd.blockchain.ledger.core.LedgerManager; | ||||
import com.jd.blockchain.ledger.core.LedgerRepository; | 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.LedgerTransactionContext; | ||||
import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; | import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; | ||||
import com.jd.blockchain.ledger.core.OperationHandleRegisteration; | 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.TransactionBatchProcessor; | ||||
import com.jd.blockchain.ledger.core.UserAccount; | import com.jd.blockchain.ledger.core.UserAccount; | ||||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | ||||
@@ -85,8 +92,9 @@ public class TransactionBatchProcessorTest { | |||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | ||||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | 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(); | BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); | ||||
@@ -108,6 +116,20 @@ public class TransactionBatchProcessorTest { | |||||
assertEquals(TransactionState.SUCCESS, txResp.getExecutionState()); | 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 | @Test | ||||
public void testMultiTxsProcess() { | public void testMultiTxsProcess() { | ||||
final MemoryKVStorage STORAGE = new MemoryKVStorage(); | final MemoryKVStorage STORAGE = new MemoryKVStorage(); | ||||
@@ -130,8 +152,9 @@ public class TransactionBatchProcessorTest { | |||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | ||||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | 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(); | BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); | ||||
@@ -187,8 +210,9 @@ public class TransactionBatchProcessorTest { | |||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | ||||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | 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(); | BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); | ||||
@@ -267,8 +291,9 @@ public class TransactionBatchProcessorTest { | |||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | ||||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | 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(); | BlockchainKeypair dataAccountKeypair = BlockchainKeyGenerator.getInstance().generate(); | ||||
TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_DataAccountReg(dataAccountKeypair, | TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_DataAccountReg(dataAccountKeypair, | ||||
@@ -293,7 +318,8 @@ public class TransactionBatchProcessorTest { | |||||
newBlockEditor = ledgerRepo.createNextBlock(); | newBlockEditor = ledgerRepo.createNextBlock(); | ||||
previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); | 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(txreq1); | ||||
txbatchProcessor.schedule(txreq2); | txbatchProcessor.schedule(txreq2); | ||||
@@ -316,7 +342,7 @@ public class TransactionBatchProcessorTest { | |||||
assertNotNull(v1_1); | assertNotNull(v1_1); | ||||
assertNotNull(v2); | assertNotNull(v2); | ||||
assertNotNull(v3); | assertNotNull(v3); | ||||
assertEquals("V-1-1", v1_0.getValue().toUTF8String()); | assertEquals("V-1-1", v1_0.getValue().toUTF8String()); | ||||
assertEquals("V-1-2", v1_1.getValue().toUTF8String()); | assertEquals("V-1-2", v1_1.getValue().toUTF8String()); | ||||
assertEquals("V-2-1", v2.getValue().toUTF8String()); | assertEquals("V-2-1", v2.getValue().toUTF8String()); | ||||
@@ -332,7 +358,8 @@ public class TransactionBatchProcessorTest { | |||||
newBlockEditor = ledgerRepo.createNextBlock(); | newBlockEditor = ledgerRepo.createNextBlock(); | ||||
previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); | 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(txreq5); | ||||
txbatchProcessor.schedule(txreq6); | txbatchProcessor.schedule(txreq6); | ||||
@@ -343,11 +370,13 @@ public class TransactionBatchProcessorTest { | |||||
BytesValue v1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1"); | BytesValue v1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1"); | ||||
v3 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K3"); | 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); | 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); | assertEquals(1, k3_version); | ||||
assertNotNull(v1); | assertNotNull(v1); | ||||
assertNotNull(v3); | assertNotNull(v3); | ||||
assertEquals("V-1-2", v1.getValue().toUTF8String()); | 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 | * @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() { | public LedgerPrivilege() { | ||||
super(CODE_INDEXER); | |||||
} | } | ||||
public LedgerPrivilege(byte[] codeBytes) { | 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; | public static final int MAX_ROLE_NAME_LENGTH = 20; | ||||
long getRoleCount(); | long getRoleCount(); | ||||
/** | |||||
* 加入新的角色授权; <br> | |||||
* | |||||
* 如果指定的角色已经存在,则引发 {@link LedgerException} 异常; | |||||
* | |||||
* @param roleName 角色名称;不能超过 {@link #MAX_ROLE_NAME_LENGTH} 个 Unicode 字符; | |||||
* @param ledgerPrivilege | |||||
* @param txPrivilege | |||||
*/ | |||||
long addRolePrivilege(String roleName, Privileges privileges); | |||||
/** | /** | ||||
* 加入新的角色授权; <br> | * 加入新的角色授权; <br> | ||||
@@ -6,35 +6,28 @@ package com.jd.blockchain.ledger; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class RolePrivileges implements PrivilegeSet { | |||||
public class RolePrivileges extends Privileges { | |||||
private String roleName; | private String roleName; | ||||
private long version; | private long version; | ||||
private LedgerPrivilege ledgerPrivilege; | |||||
private TransactionPrivilege txPrivilege; | |||||
public RolePrivileges(String roleName, long version) { | public RolePrivileges(String roleName, long version) { | ||||
this.roleName = roleName; | this.roleName = roleName; | ||||
this.version = version; | this.version = version; | ||||
this.ledgerPrivilege = new LedgerPrivilege(); | |||||
this.txPrivilege = new TransactionPrivilege(); | |||||
} | } | ||||
public RolePrivileges(String roleName, long version, PrivilegeSet privilege) { | public RolePrivileges(String roleName, long version, PrivilegeSet privilege) { | ||||
super(privilege); | |||||
this.roleName = roleName; | this.roleName = roleName; | ||||
this.version = version; | 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.roleName = roleName; | ||||
this.version = version; | this.version = version; | ||||
this.ledgerPrivilege = ledgerPrivilege; | |||||
this.txPrivilege = txPrivilege; | |||||
} | } | ||||
public String getRoleName() { | public String getRoleName() { | ||||
@@ -45,22 +38,4 @@ public class RolePrivileges implements PrivilegeSet { | |||||
return version; | 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; | 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() { | public TransactionPrivilege() { | ||||
super(CODE_INDEXER); | |||||
} | } | ||||
public TransactionPrivilege(byte[] codeBytes) { | 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), | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInfo; | import com.jd.blockchain.ledger.LedgerInfo; | ||||
import com.jd.blockchain.ledger.LedgerMetadata; | import com.jd.blockchain.ledger.LedgerMetadata; | ||||
import com.jd.blockchain.ledger.LedgerPermission; | |||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
import com.jd.blockchain.ledger.NodeRequest; | import com.jd.blockchain.ledger.NodeRequest; | ||||
import com.jd.blockchain.ledger.Operation; | 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.ParticipantNode; | ||||
import com.jd.blockchain.ledger.TransactionContent; | import com.jd.blockchain.ledger.TransactionContent; | ||||
import com.jd.blockchain.ledger.TransactionContentBody; | import com.jd.blockchain.ledger.TransactionContentBody; | ||||
import com.jd.blockchain.ledger.TransactionPermission; | |||||
import com.jd.blockchain.ledger.TransactionRequest; | import com.jd.blockchain.ledger.TransactionRequest; | ||||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | import com.jd.blockchain.ledger.TransactionRequestBuilder; | ||||
import com.jd.blockchain.ledger.TransactionResponse; | 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.LedgerManager; | ||||
import com.jd.blockchain.ledger.core.LedgerQueryService; | import com.jd.blockchain.ledger.core.LedgerQueryService; | ||||
import com.jd.blockchain.ledger.core.LedgerRepository; | 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.ledger.core.TransactionBatchProcessor; | ||||
import com.jd.blockchain.mocker.config.MockerConstant; | import com.jd.blockchain.mocker.config.MockerConstant; | ||||
import com.jd.blockchain.mocker.config.PresetAnswerPrompter; | import com.jd.blockchain.mocker.config.PresetAnswerPrompter; | ||||
@@ -121,7 +125,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||||
DataContractRegistry.register(ActionResponse.class); | DataContractRegistry.register(ActionResponse.class); | ||||
DataContractRegistry.register(ClientIdentifications.class); | DataContractRegistry.register(ClientIdentifications.class); | ||||
DataContractRegistry.register(ClientIdentification.class); | DataContractRegistry.register(ClientIdentification.class); | ||||
// DataContractRegistry.register(LedgerAdminInfo.class); | // DataContractRegistry.register(LedgerAdminInfo.class); | ||||
ByteArrayObjectUtil.init(); | ByteArrayObjectUtil.init(); | ||||
@@ -273,7 +277,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||||
public LedgerInfo getLedger(HashDigest ledgerHash) { | public LedgerInfo getLedger(HashDigest ledgerHash) { | ||||
return queryService.getLedger(ledgerHash); | return queryService.getLedger(ledgerHash); | ||||
} | } | ||||
@Override | @Override | ||||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | ||||
return queryService.getLedgerAdminInfo(ledgerHash); | return queryService.getLedgerAdminInfo(ledgerHash); | ||||
@@ -410,7 +414,7 @@ public class MockerNodeContext implements BlockchainQueryService { | |||||
} | } | ||||
@Override | @Override | ||||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||||
return queryService.getContract(ledgerHash, address); | return queryService.getContract(ledgerHash, address); | ||||
} | } | ||||
@@ -443,8 +447,8 @@ public class MockerNodeContext implements BlockchainQueryService { | |||||
LedgerEditor newEditor = ledgerRepository.createNextBlock(); | LedgerEditor newEditor = ledgerRepository.createNextBlock(); | ||||
LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); | LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); | ||||
LedgerDataset previousDataSet = ledgerRepository.getDataSet(latestBlock); | 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); | TransactionResponse txResp = txProc.schedule(txRequest); | ||||
TransactionBatchResultHandle handle = txProc.prepare(); | TransactionBatchResultHandle handle = txProc.prepare(); | ||||
handle.commit(); | 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.LedgerService; | ||||
import com.jd.blockchain.ledger.core.OperationHandle; | import com.jd.blockchain.ledger.core.OperationHandle; | ||||
import com.jd.blockchain.ledger.core.OperationHandleContext; | 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.ledger.core.handles.ContractLedgerContext; | ||||
import com.jd.blockchain.mocker.proxy.ExecutorProxy; | import com.jd.blockchain.mocker.proxy.ExecutorProxy; | ||||
@@ -29,7 +29,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||||
private HashDigest ledgerHash; | private HashDigest ledgerHash; | ||||
@Override | @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) { | LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | ||||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | ||||