# Conflicts: # source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminAccount.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java # source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java # source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java # source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerManagerTest.java # source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionSetTest.java # source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerInitProperties.java # source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ClientOperator.java # source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ConsensusParticipantData.java # source/peer/src/main/java/com/jd/blockchain/peer/web/ManagementController.java # source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java # source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java # source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java # source/tools/tools-capability/src/main/java/com/jd/blockchain/capability/service/SettingsInit.java # source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.javatags/1.1.0
@@ -0,0 +1,6 @@ | |||
1、网关节点移除查询接口 HTTP GET ledgers/{ledgerHash}/settings (出于设计合理性原因) | |||
2、网关节点增加查询接口 HTTP GET ledgers/{ledgerHash}/admininfo ,接口返回指定账本管理配置信息; |
@@ -8,12 +8,4 @@ | |||
<version>1.1.0-SNAPSHOT</version> | |||
</parent> | |||
<artifactId>base</artifactId> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.slf4j</groupId> | |||
<artifactId>slf4j-api</artifactId> | |||
</dependency> | |||
</dependencies> | |||
</project> |
@@ -8,11 +8,11 @@ package com.jd.blockchain.consts; | |||
*/ | |||
public interface DataCodes { | |||
public static final int BYTES_VALUE = 0x80; | |||
public static final int BYTES_VALUE_LIST = 0x81; | |||
public static final int BYTES_VALUE = 0x080; | |||
public static final int BYTES_VALUE_LIST = 0x081; | |||
public static final int BLOCK_CHAIN_IDENTITY = 0x90; | |||
public static final int BLOCK_CHAIN_IDENTITY = 0x090; | |||
public static final int BLOCK = 0x100; | |||
@@ -22,6 +22,8 @@ public interface DataCodes { | |||
public static final int DATA_SNAPSHOT = 0x130; | |||
// public static final int LEDGER_ADMIN_DATA = 0x131; | |||
public static final int TX = 0x200; | |||
public static final int TX_LEDGER = 0x201; | |||
@@ -55,12 +57,37 @@ public interface DataCodes { | |||
public static final int TX_RESPONSE = 0x360; | |||
public static final int TX_OP_RESULT = 0x370; | |||
public static final int TX_OP_ROLE_CONFIGURE = 0x370; | |||
public static final int TX_OP_ROLE_CONFIGURE_ENTRY = 0x371; | |||
public static final int TX_OP_USER_ROLES_AUTHORIZE = 0x372; | |||
public static final int TX_OP_USER_ROLE_AUTHORIZE_ENTRY = 0x373; | |||
// enum types of permissions; | |||
public static final int ENUM_TX_PERMISSION = 0x401; | |||
public static final int ENUM_LEDGER_PERMISSION = 0x402; | |||
public static final int ENUM_MULTI_ROLES_POLICY = 0x403; | |||
public static final int PRIVILEGE_SET = 0x410; | |||
public static final int ROLE_SET = 0x411; | |||
public static final int SECURITY_INIT_SETTING = 0x420; | |||
public static final int SECURITY_ROLE_INIT_SETTING = 0x421; | |||
public static final int SECURITY_USER_AUTH_INIT_SETTING = 0x422; | |||
// contract types of metadata; | |||
public static final int METADATA = 0x600; | |||
public static final int METADATA_V2 = 0x601; | |||
public static final int METADATA_INIT_SETTING = 0x610; | |||
public static final int METADATA_INIT_PERMISSION = 0x611; | |||
public static final int METADATA_INIT_PROPOSAL = 0x611; | |||
public static final int METADATA_INIT_DECISION = 0x612; | |||
@@ -68,6 +95,15 @@ public interface DataCodes { | |||
public static final int METADATA_CONSENSUS_PARTICIPANT = 0x621; | |||
// public static final int METADATA_CONSENSUS_NODE = 0x630; | |||
// | |||
// public static final int METADATA_CONSENSUS_SETTING = 0x631; | |||
// | |||
// public static final int METADATA_PARTICIPANT_INFO = 0x640; | |||
public static final int METADATA_CRYPTO_SETTING = 0x642; | |||
// public static final int METADATA_CONSENSUS_NODE = 0x630; | |||
public static final int METADATA_CONSENSUS_SETTING = 0x631; | |||
@@ -88,11 +124,10 @@ public interface DataCodes { | |||
public static final int DATA = 0x900; | |||
//contract related; | |||
// contract related; | |||
public static final int CONTRACT = 0xA00; | |||
//...0xA19 | |||
// ...0xA19 | |||
public static final int HASH = 0xB00; | |||
public static final int HASH_OBJECT = 0xB10; | |||
@@ -21,10 +21,10 @@ import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.ParticipantInfo; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.PropertiesUtils; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
@@ -134,7 +134,7 @@ public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilde | |||
String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | |||
String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | |||
PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey); | |||
PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey); | |||
// PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | |||
resolvingProps.remove(keyOfPubkey); | |||
@@ -7,12 +7,12 @@ import java.io.InputStream; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.sdk.BlockchainService; | |||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
import com.jd.blockchain.utils.net.NetworkAddress; | |||
@@ -30,8 +30,8 @@ public enum ContractDeployExeUtil { | |||
PubKey pub = null; | |||
PrivKey prv = null; | |||
try { | |||
prv = KeyGenCommand.readPrivKey(prvPath, KeyGenCommand.encodePassword(rawPassword)); | |||
pub = KeyGenCommand.readPubKey(pubPath); | |||
prv = KeyGenUtils.readPrivKey(prvPath, KeyGenUtils.encodePassword(rawPassword)); | |||
pub = KeyGenUtils.readPubKey(pubPath); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
@@ -47,7 +47,7 @@ public enum ContractDeployExeUtil { | |||
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | |||
pub = contractKeyPair.getPubKey(); | |||
}else { | |||
pub = KeyGenCommand.readPubKey(pubPath); | |||
pub = KeyGenUtils.readPubKey(pubPath); | |||
} | |||
} catch (Exception e) { | |||
@@ -1,10 +1,10 @@ | |||
package com.jd.blockchain; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
import com.jd.blockchain.utils.StringUtils; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
import com.jd.blockchain.utils.io.FileUtils; | |||
@@ -102,8 +102,8 @@ public class ContractDeployMojo extends AbstractMojo { | |||
byte[] contractBytes = FileUtils.readBytes(contractPath); | |||
PrivKey prv = KeyGenCommand.decodePrivKeyWithRawPassword(prvKey, password); | |||
PubKey pub = KeyGenCommand.decodePubKey(pubKey); | |||
PrivKey prv = KeyGenUtils.decodePrivKeyWithRawPassword(prvKey, password); | |||
PubKey pub = KeyGenUtils.decodePubKey(pubKey); | |||
BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv); | |||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||
@@ -0,0 +1,187 @@ | |||
package com.jd.blockchain.crypto; | |||
import java.util.Arrays; | |||
import javax.crypto.SecretKey; | |||
import com.jd.blockchain.utils.ConsoleUtils; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.FileUtils; | |||
import com.jd.blockchain.utils.security.AESUtils; | |||
import com.jd.blockchain.utils.security.DecryptionException; | |||
import com.jd.blockchain.utils.security.ShaUtils; | |||
public class KeyGenUtils { | |||
private static final byte[] PUB_KEY_FILE_MAGICNUM = { (byte) 0xFF, 112, 117, 98 }; | |||
private static final byte[] PRIV_KEY_FILE_MAGICNUM = { (byte) 0x00, 112, 114, 118 }; | |||
/** | |||
* 公钥编码输出为 Base58 字符; | |||
* | |||
* @param pubKey | |||
* @return | |||
*/ | |||
public static String encodePubKey(PubKey pubKey) { | |||
byte[] pubKeyBytes = BytesUtils.concat(PUB_KEY_FILE_MAGICNUM, pubKey.toBytes()); | |||
String base58PubKey = Base58Utils.encode(pubKeyBytes); | |||
return base58PubKey; | |||
} | |||
public static PubKey decodePubKey(String base58PubKey) { | |||
byte[] keyBytes = Base58Utils.decode(base58PubKey); | |||
return decodePubKey(keyBytes); | |||
} | |||
public static String encodePrivKey(PrivKey privKey, String base58Pwd) { | |||
byte[] pwdBytes = Base58Utils.decode(base58Pwd); | |||
return encodePrivKey(privKey, pwdBytes); | |||
} | |||
public static String encodePrivKey(PrivKey privKey, byte[] pwdBytes) { | |||
byte[] encodedPrivKeyBytes = encryptPrivKey(privKey, pwdBytes); | |||
String base58PrivKey = Base58Utils.encode(encodedPrivKeyBytes); | |||
return base58PrivKey; | |||
} | |||
public static byte[] encryptPrivKey(PrivKey privKey, byte[] pwdBytes) { | |||
SecretKey userKey = AESUtils.generateKey128(pwdBytes); | |||
byte[] encryptedPrivKeyBytes = AESUtils.encrypt(privKey.toBytes(), userKey); | |||
return BytesUtils.concat(PRIV_KEY_FILE_MAGICNUM, encryptedPrivKeyBytes); | |||
} | |||
/** | |||
* @param encodedPubKeyBytes | |||
* @return | |||
*/ | |||
private static PubKey decodePubKeyBytes(byte[] encodedPubKeyBytes) { | |||
byte[] pubKeyBytes = Arrays.copyOfRange(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM.length, | |||
encodedPubKeyBytes.length); | |||
return new PubKey(pubKeyBytes); | |||
} | |||
public static PrivKey decryptedPrivKeyBytes(byte[] encodedPrivKeyBytes, byte[] pwdBytes) { | |||
// Read privKye; | |||
SecretKey userKey = AESUtils.generateKey128(pwdBytes); | |||
byte[] encryptedKeyBytes = Arrays.copyOfRange(encodedPrivKeyBytes, PRIV_KEY_FILE_MAGICNUM.length, | |||
encodedPrivKeyBytes.length); | |||
try { | |||
byte[] plainKeyBytes = AESUtils.decrypt(encryptedKeyBytes, userKey); | |||
return new PrivKey(plainKeyBytes); | |||
} catch (DecryptionException e) { | |||
throw new DecryptionException("Invalid password!", e); | |||
} | |||
} | |||
public static PubKey readPubKey(String keyFile) { | |||
String base58KeyString = FileUtils.readText(keyFile); | |||
return decodePubKey(base58KeyString); | |||
} | |||
/** | |||
* 解码公钥; | |||
* | |||
* @param encodedPubKeyBytes 从公钥; | |||
* @return | |||
*/ | |||
public static PubKey decodePubKey(byte[] encodedPubKeyBytes) { | |||
if (BytesUtils.startsWith(encodedPubKeyBytes, PUB_KEY_FILE_MAGICNUM)) { | |||
// Read pubKey; | |||
return decodePubKeyBytes(encodedPubKeyBytes); | |||
} | |||
throw new IllegalArgumentException("The specified bytes is not valid PubKey generated by the KeyGen tool!"); | |||
} | |||
/** | |||
* 从控制台读取加密口令,以二进制数组形式返回原始口令的一次SHA256的结果; | |||
* | |||
* @return | |||
*/ | |||
public static byte[] readPassword() { | |||
byte[] pwdBytes = ConsoleUtils.readPassword(); | |||
return ShaUtils.hash_256(pwdBytes); | |||
} | |||
/** | |||
* 对指定的原始密码进行编码生成用于加解密的密码; | |||
* | |||
* @param rawPassword | |||
* @return | |||
*/ | |||
public static byte[] encodePassword(String rawPassword) { | |||
byte[] pwdBytes = BytesUtils.toBytes(rawPassword, "UTF-8"); | |||
return ShaUtils.hash_256(pwdBytes); | |||
} | |||
/** | |||
* 对指定的原始密码进行编码生成用于加解密的密码; | |||
* | |||
* @param rawPassword | |||
* @return | |||
*/ | |||
public static String encodePasswordAsBase58(String rawPassword) { | |||
return Base58Utils.encode(encodePassword(rawPassword)); | |||
} | |||
/** | |||
* 从控制台读取加密口令,以Base58字符串形式返回口令的一次SHA256的结果; | |||
* | |||
* @return | |||
*/ | |||
public static String readPasswordString() { | |||
return Base58Utils.encode(readPassword()); | |||
} | |||
public static PrivKey readPrivKey(String keyFile, String base58Pwd) { | |||
return readPrivKey(keyFile, Base58Utils.decode(base58Pwd)); | |||
} | |||
/** | |||
* 从文件读取私钥; | |||
* | |||
* @param keyFile | |||
* @param pwdBytes | |||
* @return | |||
*/ | |||
public static PrivKey readPrivKey(String keyFile, byte[] pwdBytes) { | |||
String base58KeyString = FileUtils.readText(keyFile); | |||
byte[] keyBytes = Base58Utils.decode(base58KeyString); | |||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||
} | |||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||
} | |||
public static PrivKey decodePrivKey(String base58Key, String base58Pwd) { | |||
byte[] decryptedKey = Base58Utils.decode(base58Pwd); | |||
return decodePrivKey(base58Key, decryptedKey); | |||
} | |||
public static PrivKey decodePrivKey(String base58Key, byte[] pwdBytes) { | |||
byte[] keyBytes = Base58Utils.decode(base58Key); | |||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||
} | |||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||
} | |||
public static PrivKey decodePrivKeyWithRawPassword(String base58Key, String rawPassword) { | |||
byte[] pwdBytes = encodePassword(rawPassword); | |||
byte[] keyBytes = Base58Utils.decode(base58Key); | |||
if (!BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM)) { | |||
throw new IllegalArgumentException("The specified file is not a private key file!"); | |||
} | |||
return decryptedPrivKeyBytes(keyBytes, pwdBytes); | |||
} | |||
public static boolean isPubKeyBytes(byte[] keyBytes) { | |||
return BytesUtils.startsWith(keyBytes, PUB_KEY_FILE_MAGICNUM); | |||
} | |||
public static boolean isPrivKeyBytes(byte[] keyBytes) { | |||
return BytesUtils.startsWith(keyBytes, PRIV_KEY_FILE_MAGICNUM); | |||
} | |||
} |
@@ -18,15 +18,13 @@ public class GatewayBooter { | |||
writePID(); | |||
GatewayServerBooter.main(args); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
System.err.println("Error!!! --[" + e.getClass().getName() + "] " + e.getMessage()); | |||
} | |||
} | |||
private static final void writePID() throws Exception { | |||
URL url = GatewayBooter.class | |||
.getProtectionDomain() | |||
.getCodeSource() | |||
.getLocation(); | |||
URL url = GatewayBooter.class.getProtectionDomain().getCodeSource().getLocation(); | |||
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | |||
if (currPath.contains("!/")) { | |||
currPath = currPath.substring(5, currPath.indexOf("!/")); | |||
@@ -40,6 +38,10 @@ public class GatewayBooter { | |||
String pidFilePath = homeDir + File.separator + "bin" + File.separator + "PID.log"; | |||
File pidFile = new File(pidFilePath); | |||
if (!pidFile.exists()) { | |||
File dir = pidFile.getParentFile(); | |||
if (!dir.exists()) { | |||
dir.mkdirs(); | |||
} | |||
pidFile.createNewFile(); | |||
} | |||
String name = ManagementFactory.getRuntimeMXBean().getName(); | |||
@@ -75,7 +75,6 @@ | |||
<dependency> | |||
<groupId>commons-io</groupId> | |||
<artifactId>commons-io</artifactId> | |||
<version>${commons-io.version}</version> | |||
</dependency> | |||
<dependency> | |||
@@ -98,18 +97,13 @@ | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-web</artifactId> | |||
<exclusions> | |||
<exclusion> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-logging</artifactId> | |||
</exclusion> | |||
</exclusions> | |||
</dependency> | |||
<dependency> | |||
<!-- <dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-log4j2</artifactId> | |||
</dependency> | |||
</dependency> --> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
@@ -5,20 +5,20 @@ import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||
import org.apache.commons.io.FileUtils; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.context.ConfigurableApplicationContext; | |||
import org.springframework.core.io.ClassPathResource; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||
import com.jd.blockchain.utils.ArgumentSet; | |||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||
import com.jd.blockchain.utils.BaseConstant; | |||
import com.jd.blockchain.utils.ConsoleUtils; | |||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||
public class GatewayServerBooter { | |||
@@ -88,19 +88,19 @@ public class GatewayServerBooter { | |||
String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | |||
if (base58Pwd == null || base58Pwd.length() == 0) { | |||
base58Pwd = KeyGenCommand.readPasswordString(); | |||
base58Pwd = KeyGenUtils.readPasswordString(); | |||
} | |||
// 加载密钥; | |||
PubKey pubKey = KeyGenCommand.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||
PubKey pubKey = KeyGenUtils.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||
PrivKey privKey = null; | |||
String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | |||
if (base58PrivKey == null) { | |||
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | |||
privKey = KeyGenCommand.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||
} else { | |||
privKey = KeyGenCommand.decodePrivKey(base58PrivKey, base58Pwd); | |||
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd); | |||
} | |||
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | |||
} | |||
@@ -1,50 +0,0 @@ | |||
package com.jd.blockchain.gateway.service; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.sdk.ContractSettings; | |||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* queryService only for gateway; | |||
* @Author zhaogw | |||
* @Date 2019/2/22 10:37 | |||
*/ | |||
public interface GatewayQueryService { | |||
/** | |||
* get all ledgers hashs; | |||
* @param fromIndex | |||
* @param count | |||
*/ | |||
HashDigest[] getLedgersHash(int fromIndex, int count); | |||
/** | |||
* get the participants by range; | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* 获取账本初始化配置信息 | |||
* | |||
* @param ledgerHash | |||
* 账本Hash | |||
* @return | |||
*/ | |||
LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash); | |||
/** | |||
* 获取账本指定合约信息 | |||
* | |||
* @param ledgerHash | |||
* 账本Hash | |||
* @param address | |||
* 合约地址 | |||
* @return | |||
*/ | |||
ContractSettings getContractSettings(HashDigest ledgerHash, String address); | |||
} |
@@ -1,144 +0,0 @@ | |||
package com.jd.blockchain.gateway.service; | |||
import com.jd.blockchain.consensus.ConsensusProvider; | |||
import com.jd.blockchain.consensus.ConsensusProviders; | |||
import com.jd.blockchain.consensus.ConsensusSettings; | |||
import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | |||
import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.gateway.PeerService; | |||
import com.jd.blockchain.gateway.decompiler.utils.DecompilerUtils; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.sdk.ContractSettings; | |||
import com.jd.blockchain.sdk.LedgerInitSettings; | |||
import com.jd.blockchain.utils.QueryUtil; | |||
import com.jd.blockchain.utils.codec.HexUtils; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Component; | |||
import java.util.Arrays; | |||
/** | |||
* @Author zhaogw | |||
* @Date 2019/2/22 10:39 | |||
*/ | |||
@Component | |||
public class GatewayQueryServiceHandler implements GatewayQueryService { | |||
@Autowired | |||
private PeerService peerService; | |||
@Override | |||
public HashDigest[] getLedgersHash(int fromIndex, int count) { | |||
HashDigest ledgersHash[] = peerService.getQueryService().getLedgerHashs(); | |||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,ledgersHash.length); | |||
HashDigest ledgersHashNew[] = Arrays.copyOfRange(ledgersHash,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||
return ledgersHashNew; | |||
} | |||
@Override | |||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash, int fromIndex, int count) { | |||
ParticipantNode participantNode[] = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||
int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex,count,participantNode.length); | |||
ParticipantNode participantNodesNew[] = Arrays.copyOfRange(participantNode,indexAndCount[0],indexAndCount[0]+indexAndCount[1]); | |||
return participantNodesNew; | |||
} | |||
@Override | |||
public LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash) { | |||
ParticipantNode[] participantNodes = peerService.getQueryService().getConsensusParticipants(ledgerHash); | |||
LedgerMetadata ledgerMetadata = peerService.getQueryService().getLedgerMetadata(ledgerHash); | |||
return initLedgerInitSettings(participantNodes, ledgerMetadata); | |||
} | |||
@Override | |||
public ContractSettings getContractSettings(HashDigest ledgerHash, String address) { | |||
ContractInfo contractInfo = peerService.getQueryService().getContract(ledgerHash, address); | |||
return contractSettings(contractInfo); | |||
} | |||
private ContractSettings contractSettings(ContractInfo contractInfo) { | |||
ContractSettings contractSettings = new ContractSettings(contractInfo.getAddress(), contractInfo.getPubKey(), contractInfo.getRootHash()); | |||
byte[] chainCodeBytes = contractInfo.getChainCode(); | |||
// 将反编译chainCode | |||
String mainClassJava = DecompilerUtils.decompileMainClassFromBytes(chainCodeBytes); | |||
contractSettings.setChainCode(mainClassJava); | |||
return contractSettings; | |||
} | |||
/** | |||
* 初始化账本配置 | |||
* | |||
* @param participantNodes | |||
* 参与方列表 | |||
* @param ledgerMetadata | |||
* 账本元数据 | |||
* @return | |||
*/ | |||
private LedgerInitSettings initLedgerInitSettings(ParticipantNode[] participantNodes, LedgerMetadata ledgerMetadata) { | |||
LedgerInitSettings ledgerInitSettings = new LedgerInitSettings(); | |||
// 设置参与方 | |||
ledgerInitSettings.setParticipantNodes(participantNodes); | |||
// 设置共识设置 | |||
ledgerInitSettings.setConsensusSettings(initConsensusSettings(ledgerMetadata)); | |||
// 设置参与方根Hash | |||
ledgerInitSettings.setParticipantsHash(ledgerMetadata.getParticipantsHash()); | |||
// 设置算法配置 | |||
ledgerInitSettings.setCryptoSetting(ledgerMetadata.getSetting().getCryptoSetting()); | |||
// 设置种子 | |||
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed())); | |||
// 设置共识协议 | |||
ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider()); | |||
return ledgerInitSettings; | |||
} | |||
/** | |||
* 初始化账本种子信息 | |||
* | |||
* @param seedBytes | |||
* 种子的字节数组显示 | |||
* @return | |||
* 种子以十六进制方式显示,为方便阅读,每隔八个字符中间以"-"分割 | |||
*/ | |||
private String initSeed(byte[] seedBytes) { | |||
String seedString = HexUtils.encode(seedBytes); | |||
// 每隔八个字符中加入一个一个横线 | |||
StringBuffer seed = new StringBuffer(); | |||
for( int i = 0; i < seedString.length(); i++) { | |||
char c = seedString.charAt(i); | |||
if (i != 0 && i % 8 == 0) { | |||
seed.append("-"); | |||
} | |||
seed.append(c); | |||
} | |||
return seed.toString(); | |||
} | |||
/** | |||
* 初始化共识配置 | |||
* | |||
* @param ledgerMetadata | |||
* 账本元数据 | |||
* @return | |||
*/ | |||
private ConsensusSettings initConsensusSettings(LedgerMetadata ledgerMetadata) { | |||
String consensusProvider = ledgerMetadata.getSetting().getConsensusProvider(); | |||
ConsensusProvider provider = ConsensusProviders.getProvider(consensusProvider); | |||
byte[] consensusSettingsBytes = ledgerMetadata.getSetting().getConsensusSetting().toBytes(); | |||
return provider.getSettingsFactory().getConsensusSettingsEncoder().decode(consensusSettingsBytes); | |||
} | |||
} |
@@ -35,6 +35,9 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer { | |||
JSONSerializeUtils.disableCircularReferenceDetect(); | |||
JSONSerializeUtils.configStringSerializer(ByteArray.class); | |||
DataContractRegistry.register(BftsmartNodeSettings.class); | |||
DataContractRegistry.register(LedgerAdminInfo.class); | |||
} | |||
@@ -1,26 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
public interface AccountPrivilege { | |||
/** | |||
* 数据“读”的操作码; | |||
* | |||
* @return | |||
*/ | |||
byte getReadingOpCode(); | |||
/** | |||
* “写”的操作码; | |||
* | |||
* @return | |||
*/ | |||
byte getWrittingOpCode(); | |||
/** | |||
* 其它的扩展操作码; | |||
* | |||
* @return | |||
*/ | |||
byte[] getExtOpCodes(); | |||
} |
@@ -12,6 +12,7 @@ import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -48,6 +49,10 @@ public class AccountSet implements Transactional, MerkleProvable { | |||
public boolean isReadonly() { | |||
return merkleDataset.isReadonly(); | |||
} | |||
void setReadonly() { | |||
merkleDataset.setReadonly(); | |||
} | |||
public AccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
@@ -65,10 +70,6 @@ public class AccountSet implements Transactional, MerkleProvable { | |||
this.accessPolicy = accessPolicy; | |||
} | |||
// public HashDigest getAccountRootHash() { | |||
// return merkleDataset.getRootHash(); | |||
// } | |||
@Override | |||
public HashDigest getRootHash() { | |||
return merkleDataset.getRootHash(); | |||
@@ -1,168 +0,0 @@ | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//import com.jd.blockchain.crypto.hash.HashDigest; | |||
// | |||
//import my.utils.Scratchable; | |||
//import my.utils.io.ByteArray; | |||
//import my.utils.io.BytesUtils; | |||
//import my.utils.io.ExistancePolicyKVStorage; | |||
//import my.utils.io.VersioningKVStorage; | |||
// | |||
///** | |||
// * 可进行授权控制的数据集合; | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
//public class AuthorizableDataSet implements Scratchable { | |||
// | |||
// public static final String DATA_PREFIX = "DATA" + LedgerConsts.KEY_SEPERATOR; | |||
//// public static final String PRIVILEGE_PREFIX = "PRVL" + LedgerConsts.KEY_SEPERATOR; | |||
// | |||
// private static final String DEFAULT_PRIVILEGE_KEY = "%"; | |||
// | |||
// private DataAccessable accessable; | |||
// | |||
// protected MerkleDataSet data; | |||
// | |||
//// private PrivilegeDataSet privileges; | |||
// | |||
// /** | |||
// * Create a new Account instance; | |||
// * | |||
// * @param address | |||
// * @param pubKey | |||
// */ | |||
// protected AuthorizableDataSet(CryptoSetting merkleTreeSetting, ExistancePolicyKVStorage simpleStorage, | |||
// VersioningKVStorage versioningStorage) { | |||
// this(null, merkleTreeSetting, null, simpleStorage, versioningStorage); | |||
// } | |||
// | |||
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash, | |||
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage) { | |||
// this(dataRootHash, merkleTreeSetting, privilegeRootHash, simpleStorage, versioningStorage, false); | |||
// } | |||
// | |||
// protected AuthorizableDataSet(byte[] dataRootHash, CryptoSetting merkleTreeSetting, byte[] privilegeRootHash, | |||
// ExistancePolicyKVStorage simpleStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
// this.data = new MerkleDataSet(dataRootHash, merkleTreeSetting, | |||
// PrefixAppender.prefix(DATA_PREFIX, simpleStorage), | |||
// PrefixAppender.prefix(DATA_PREFIX, versioningStorage), readonly); | |||
// | |||
//// this.privileges = new PrivilegeDataSet(privilegeRootHash, merkleTreeSetting, | |||
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, simpleStorage), | |||
//// PrefixAppender.prefix(PRIVILEGE_PREFIX, versioningStorage), readonly); | |||
// } | |||
// | |||
// public ByteArray getDataRootHash() { | |||
// return data.getRootHash(); | |||
// } | |||
// | |||
//// public ByteArray getPrivilegeRootHash() { | |||
//// return privileges.getRootHash(); | |||
//// } | |||
// | |||
// /** | |||
// * | |||
// * @param userAddress | |||
// * @param op | |||
// * @param enable | |||
// */ | |||
// public void setPrivilege(String userAddress, byte op, boolean enable) { | |||
// | |||
// } | |||
// | |||
// /** | |||
// * | |||
// * @param op | |||
// * @param enable | |||
// */ | |||
// public void setDefaultPrivilege(byte op, boolean enable) { | |||
// } | |||
// | |||
// public boolean checkCurrentUserPrivilege() { | |||
// return false; | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getVersion(String key) { | |||
// return data.getVersion(key); | |||
// } | |||
// | |||
// protected long setString(String key, String value, long version) { | |||
// checkWritting(); | |||
// byte[] bytes = BytesUtils.toBytes(value, LedgerConsts.CHARSET); | |||
// return data.setValue(key, bytes, version); | |||
// } | |||
// | |||
// protected String getString(String key) { | |||
// checkReading(); | |||
// byte[] value = data.getValue(key); | |||
// return BytesUtils.toString(value, LedgerConsts.CHARSET); | |||
// } | |||
// | |||
// protected String getString(String key, long version) { | |||
// checkReading(); | |||
// byte[] value = data.getValue(key, version); | |||
// return BytesUtils.toString(value, LedgerConsts.CHARSET); | |||
// } | |||
// | |||
// protected long setValue(String key, byte[] value, long version) { | |||
// checkWritting(); | |||
// return data.setValue(key, value, version); | |||
// } | |||
// | |||
// protected byte[] getValue(String key) { | |||
// checkReading(); | |||
// return data.getValue(key); | |||
// } | |||
// | |||
// protected byte[] getValue(String key, long version) { | |||
// checkReading(); | |||
// return data.getValue(key, version); | |||
// } | |||
// | |||
// private void checkWritting() { | |||
// // Check writting enable; | |||
// } | |||
// | |||
// private void checkReading() { | |||
// // TODO Check privilege of reading; | |||
// } | |||
// | |||
// // /** | |||
// // * 数据“读”的操作码; | |||
// // * | |||
// // * @return | |||
// // */ | |||
// // protected abstract AccountPrivilege getPrivilege(); | |||
// | |||
// @Override | |||
// public boolean isUpdated() { | |||
// return data.isUpdated(); | |||
//// return data.isUpdated()|| privileges.isUpdated(); | |||
// } | |||
// | |||
// @Override | |||
// public void commit() { | |||
// if (data.isUpdated()) { | |||
// data.commit(); | |||
// } | |||
//// if (privileges.isUpdated()) { | |||
//// privileges.commit(); | |||
//// } | |||
// } | |||
// | |||
// @Override | |||
// public void cancel() { | |||
// data.cancel(); | |||
//// privileges.cancel(); | |||
// } | |||
// | |||
//} |
@@ -1,40 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
/** | |||
* {@link Authorization} 抽象了对特定用户/角色的授权信息; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface Authorization { | |||
/** | |||
* 被授权用户/角色的地址; | |||
* | |||
* @return | |||
*/ | |||
String getAddress(); | |||
/** | |||
* 授权码;<br> | |||
* | |||
* @return | |||
*/ | |||
byte[] getCode(); | |||
/** | |||
* 授权者的签名; | |||
* | |||
* @return | |||
*/ | |||
DigitalSignature getSignature(); | |||
// /** | |||
// * 授权生成的时间戳; | |||
// * @return | |||
// */ | |||
// long getTs(); | |||
} |
@@ -1,42 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class AuthorizationVO implements Authorization { | |||
private String address; | |||
private byte[] code; | |||
private DigitalSignature signature; | |||
@Override | |||
public String getAddress() { | |||
return address; | |||
} | |||
public void setAddress(String address) { | |||
this.address = address; | |||
} | |||
@Override | |||
public byte[] getCode() { | |||
return code; | |||
} | |||
public void setCode(byte[] code) { | |||
this.code = code; | |||
} | |||
@Override | |||
public DigitalSignature getSignature() { | |||
return signature; | |||
} | |||
public void setSignature(DigitalSignature signature) { | |||
this.signature = signature; | |||
} | |||
} |
@@ -8,6 +8,7 @@ import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -64,13 +65,13 @@ public class BaseAccount implements AccountHeader, MerkleProvable, Transactional | |||
/** | |||
* Create a account instance with the specified address and pubkey and load it's | |||
* merkle dataset with the specified root hash. which is used for storing data | |||
* merkle dataset from the specified root hash. This merkle dateset is used for storing data | |||
* of this account.<br> | |||
* | |||
* @param address | |||
* @param pubKey | |||
* @param dataRootHash merkle root hash of account's data; if null be set, | |||
* create a new empty merkle dataset; | |||
* @param dataRootHash merkle root hash of account's data; if set to a null value, | |||
* an empty merkle dataset is created; | |||
* @param cryptoSetting | |||
* @param exStorage | |||
* @param verStorage | |||
@@ -1,21 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* @author hhq | |||
* @version 1.0 | |||
* @created 14-6��-2018 12:13:32 | |||
*/ | |||
public class Consensus { | |||
public P2PRealm m_P2PRealm; | |||
public Consensus(){ | |||
} | |||
public void finalize() throws Throwable { | |||
} | |||
} |
@@ -2,10 +2,10 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractAccount implements ContractInfo { | |||
@@ -0,0 +1,29 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface ContractAccountQuery { | |||
AccountHeader[] getAccounts(int fromIndex, int count); | |||
HashDigest getRootHash(); | |||
/** | |||
* 返回合约总数; | |||
* | |||
* @return | |||
*/ | |||
long getTotalCount(); | |||
MerkleProof getProof(Bytes address); | |||
boolean contains(Bytes address); | |||
ContractAccount getContract(Bytes address); | |||
ContractAccount getContract(Bytes address, long version); | |||
} |
@@ -5,12 +5,13 @@ import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class ContractAccountSet implements MerkleProvable, Transactional { | |||
public class ContractAccountSet implements MerkleProvable, Transactional, ContractAccountQuery { | |||
private AccountSet accountSet; | |||
@@ -25,6 +26,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return accountSet.getAccounts(fromIndex,count); | |||
} | |||
@@ -33,6 +35,10 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
@@ -43,6 +49,7 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotalCount() { | |||
return accountSet.getTotalCount(); | |||
} | |||
@@ -52,15 +59,18 @@ public class ContractAccountSet implements MerkleProvable, Transactional { | |||
return accountSet.getProof(address); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public ContractAccount getContract(Bytes address) { | |||
BaseAccount accBase = accountSet.getAccount(address); | |||
return new ContractAccount(accBase); | |||
} | |||
@Override | |||
public ContractAccount getContract(Bytes address, long version) { | |||
BaseAccount accBase = accountSet.getAccount(address, version); | |||
return new ContractAccount(accBase); | |||
@@ -82,7 +82,7 @@ public class CryptoConfig implements CryptoSetting { | |||
public void setHashAlgorithm(short hashAlgorithm) { | |||
if (codeAlgorithms == null || !codeAlgorithms.containsKey(hashAlgorithm)) { | |||
throw new LedgerException("The specified algorithm[" + hashAlgorithm + "] has no provider!"); | |||
throw new LedgerException("Current CryptoConfig has no crypto provider!"); | |||
} | |||
this.hashAlgorithm = hashAlgorithm; | |||
} | |||
@@ -8,6 +8,7 @@ import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.KVDataObject; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccount implements AccountHeader, MerkleProvable { | |||
@@ -0,0 +1,32 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface DataAccountQuery { | |||
AccountHeader[] getAccounts(int fromIndex, int count); | |||
HashDigest getRootHash(); | |||
long getTotalCount(); | |||
/** | |||
* 返回账户的存在性证明; | |||
*/ | |||
MerkleProof getProof(Bytes address); | |||
/** | |||
* 返回数据账户; <br> | |||
* 如果不存在,则返回 null; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DataAccount getDataAccount(Bytes address); | |||
DataAccount getDataAccount(Bytes address, long version); | |||
} |
@@ -5,12 +5,13 @@ import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class DataAccountSet implements MerkleProvable, Transactional { | |||
public class DataAccountSet implements MerkleProvable, Transactional, DataAccountQuery { | |||
private AccountSet accountSet; | |||
@@ -25,6 +26,7 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||
accountSet = new AccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return accountSet.getAccounts(fromIndex, count); | |||
} | |||
@@ -33,11 +35,16 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
@Override | |||
public long getTotalCount() { | |||
return accountSet.getTotalCount(); | |||
} | |||
@@ -63,6 +70,7 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public DataAccount getDataAccount(Bytes address) { | |||
BaseAccount accBase = accountSet.getAccount(address); | |||
if (accBase == null) { | |||
@@ -71,6 +79,7 @@ public class DataAccountSet implements MerkleProvable, Transactional { | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public DataAccount getDataAccount(Bytes address, long version) { | |||
BaseAccount accBase = accountSet.getAccount(address, version); | |||
return new DataAccount(accBase); | |||
@@ -0,0 +1,132 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import org.springframework.stereotype.Component; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.core.handles.ContractCodeDeployOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.DataAccountKVSetOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.DataAccountRegisterOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.JVMContractEventSendOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.LedgerInitOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.RolesConfigureOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.UserAuthorizeOperationHandle; | |||
import com.jd.blockchain.ledger.core.handles.UserRegisterOperationHandle; | |||
import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; | |||
import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; | |||
import com.jd.blockchain.transaction.LedgerInitOpTemplate; | |||
import com.jd.blockchain.transaction.RolesConfigureOpTemplate; | |||
import com.jd.blockchain.transaction.UserAuthorizeOpTemplate; | |||
import com.jd.blockchain.transaction.UserRegisterOpTemplate; | |||
@Component | |||
public class DefaultOperationHandleRegisteration implements OperationHandleRegisteration { | |||
private static Map<Class<?>, OperationHandle> DEFAULT_HANDLES = new HashMap<>(); | |||
private Map<Class<?>, OperationHandle> handles = new ConcurrentHashMap<>(); | |||
static { | |||
registerDefaultHandle(new LedgerInitOperationHandle()); | |||
registerDefaultHandle(new RolesConfigureOperationHandle()); | |||
registerDefaultHandle(new UserAuthorizeOperationHandle()); | |||
registerDefaultHandle(new UserRegisterOperationHandle()); | |||
registerDefaultHandle(new DataAccountKVSetOperationHandle()); | |||
registerDefaultHandle(new DataAccountRegisterOperationHandle()); | |||
registerDefaultHandle(new ContractCodeDeployOperationHandle()); | |||
registerDefaultHandle(new JVMContractEventSendOperationHandle()); | |||
} | |||
private static void registerDefaultHandle(OperationHandle handle) { | |||
DEFAULT_HANDLES.put(handle.getOperationType(), handle); | |||
} | |||
/** | |||
* 注册操作处理器;此方法将覆盖默认的操作处理器配置; | |||
* | |||
* @param handle | |||
*/ | |||
public void registerHandle(OperationHandle handle) { | |||
List<Class<?>> opTypes = new ArrayList<Class<?>>(); | |||
for (Class<?> opType : handles.keySet()) { | |||
if (opType.isAssignableFrom(handle.getOperationType())) { | |||
opTypes.add(opType); | |||
} | |||
} | |||
for (Class<?> opType : opTypes) { | |||
handles.put(opType, handle); | |||
} | |||
handles.put(handle.getOperationType(), handle); | |||
} | |||
private OperationHandle getRegisteredHandle(Class<?> operationType) { | |||
OperationHandle hdl = handles.get(operationType); | |||
if (hdl == null) { | |||
hdl = DEFAULT_HANDLES.get(operationType); | |||
//按“操作类型”的继承关系匹配; | |||
if (hdl == null) { | |||
for (Class<?> opType : handles.keySet()) { | |||
if (opType.isAssignableFrom(operationType)) { | |||
hdl = handles.get(opType); | |||
break; | |||
} | |||
} | |||
} | |||
if (hdl == null) { | |||
for (Class<?> opType : DEFAULT_HANDLES.keySet()) { | |||
if (opType.isAssignableFrom(operationType)) { | |||
hdl = DEFAULT_HANDLES.get(opType); | |||
break; | |||
} | |||
} | |||
} | |||
if (hdl != null) { | |||
handles.put(operationType, hdl); | |||
} | |||
} | |||
return hdl; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration#getHandle( | |||
* java.lang.Class) | |||
*/ | |||
@Override | |||
public OperationHandle getHandle(Class<? extends Operation> operationType) { | |||
OperationHandle hdl = getRegisteredHandle(operationType); | |||
if (hdl == null) { | |||
throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!"); | |||
} | |||
return hdl; | |||
} | |||
private static class OpHandleStub { | |||
private Class<? extends Operation> operationType; | |||
private OperationHandle operationHandle; | |||
} | |||
} |
@@ -0,0 +1,209 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class EmptyLedgerDataset implements LedgerDataQuery { | |||
private static final LedgerAdminDataQuery EMPTY_ADMIN_DATA = new EmptyAdminData(); | |||
private static final UserAccountQuery EMPTY_USER_ACCOUNTS = new EmptyUserAccountSet(); | |||
private static final DataAccountQuery EMPTY_DATA_ACCOUNTS = new EmptyDataAccountSet(); | |||
private static final ContractAccountQuery EMPTY_CONTRACT_ACCOUNTS = new EmptyContractAccountSet(); | |||
private static final ParticipantDataQuery EMPTY_PARTICIPANTS = new EmptyParticipantData(); | |||
@Override | |||
public LedgerAdminDataQuery getAdminDataset() { | |||
return EMPTY_ADMIN_DATA; | |||
} | |||
@Override | |||
public UserAccountQuery getUserAccountSet() { | |||
return EMPTY_USER_ACCOUNTS; | |||
} | |||
@Override | |||
public DataAccountQuery getDataAccountSet() { | |||
return EMPTY_DATA_ACCOUNTS; | |||
} | |||
@Override | |||
public ContractAccountQuery getContractAccountset() { | |||
return EMPTY_CONTRACT_ACCOUNTS; | |||
} | |||
private static class EmptyAdminData implements LedgerAdminDataQuery{ | |||
@Override | |||
public LedgerAdminInfo getAdminInfo() { | |||
return null; | |||
} | |||
@Override | |||
public ParticipantDataQuery getParticipantDataset() { | |||
return EMPTY_PARTICIPANTS; | |||
} | |||
} | |||
private static class EmptyParticipantData implements ParticipantDataQuery{ | |||
@Override | |||
public HashDigest getRootHash() { | |||
return null; | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return null; | |||
} | |||
@Override | |||
public long getParticipantCount() { | |||
return 0; | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return false; | |||
} | |||
@Override | |||
public ParticipantNode getParticipant(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public ParticipantNode[] getParticipants() { | |||
return null; | |||
} | |||
} | |||
private static class EmptyUserAccountSet implements UserAccountQuery{ | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return null; | |||
} | |||
@Override | |||
public long getTotalCount() { | |||
return 0; | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return null; | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return null; | |||
} | |||
@Override | |||
public UserAccount getUser(String address) { | |||
return null; | |||
} | |||
@Override | |||
public UserAccount getUser(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return false; | |||
} | |||
@Override | |||
public UserAccount getUser(Bytes address, long version) { | |||
return null; | |||
} | |||
} | |||
private static class EmptyDataAccountSet implements DataAccountQuery{ | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return null; | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return null; | |||
} | |||
@Override | |||
public long getTotalCount() { | |||
return 0; | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public DataAccount getDataAccount(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public DataAccount getDataAccount(Bytes address, long version) { | |||
return null; | |||
} | |||
} | |||
private static class EmptyContractAccountSet implements ContractAccountQuery{ | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return null; | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return null; | |||
} | |||
@Override | |||
public long getTotalCount() { | |||
return 0; | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return false; | |||
} | |||
@Override | |||
public ContractAccount getContract(Bytes address) { | |||
return null; | |||
} | |||
@Override | |||
public ContractAccount getContract(Bytes address, long version) { | |||
return null; | |||
} | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.utils.Bytes; | |||
class FullPermissionedSecurityManager implements LedgerSecurityManager { | |||
public static final FullPermissionedSecurityManager INSTANCE = new FullPermissionedSecurityManager(); | |||
@Override | |||
public SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||
return new FullPermissionedPolicy(endpoints, nodes); | |||
} | |||
private static class FullPermissionedPolicy implements SecurityPolicy { | |||
private Set<Bytes> endpoints; | |||
private Set<Bytes> nodes; | |||
public FullPermissionedPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) { | |||
this.endpoints = endpoints; | |||
this.nodes = nodes; | |||
} | |||
@Override | |||
public Set<Bytes> getEndpoints() { | |||
return endpoints; | |||
} | |||
@Override | |||
public Set<Bytes> getNodes() { | |||
return nodes; | |||
} | |||
@Override | |||
public boolean isEndpointEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public boolean isEndpointEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public boolean isNodeEnable(LedgerPermission permission, MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public boolean isNodeEnable(TransactionPermission permission, MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public void checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
} | |||
@Override | |||
public void checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
} | |||
@Override | |||
public void checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||
} | |||
@Override | |||
public void checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
} | |||
@Override | |||
public boolean isEndpointValid(MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public boolean isNodeValid(MultiIDsPolicy midPolicy) { | |||
return true; | |||
} | |||
@Override | |||
public void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||
} | |||
@Override | |||
public void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||
} | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
/** | |||
* @author hhq | |||
* @version 1.0 | |||
* @created 14-6��-2018 12:13:32 | |||
*/ | |||
public class Gateway extends Node { | |||
public ParticipantNode m_Participant; | |||
public Gateway(){ | |||
} | |||
public void finalize() throws Throwable { | |||
super.finalize(); | |||
} | |||
} |
@@ -1,3 +1,4 @@ | |||
package com.jd.blockchain.ledger.core; | |||
//package com.jd.blockchain.ledger.core.impl; | |||
// | |||
//import com.jd.blockchain.storage.service.ExPolicyKVStorage; |
@@ -0,0 +1,12 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||
public interface LedgerAdminDataQuery { | |||
LedgerAdminInfo getAdminInfo(); | |||
ParticipantDataQuery getParticipantDataset(); | |||
} |
@@ -0,0 +1,469 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerMetadata_V2; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.UserRolesSettings; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class LedgerAdminDataset implements Transactional, LedgerAdminDataQuery, LedgerAdminInfo { | |||
static { | |||
DataContractRegistry.register(LedgerMetadata.class); | |||
DataContractRegistry.register(LedgerMetadata_V2.class); | |||
} | |||
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminDataset.class); | |||
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_SETTING_PREFIX = "SET" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String ROLE_PRIVILEGE_PREFIX = "RPV" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String USER_ROLE_PREFIX = "URO" + LedgerConsts.KEY_SEPERATOR; | |||
private final Bytes metaPrefix; | |||
private final Bytes settingPrefix; | |||
private LedgerMetadata_V2 origMetadata; | |||
private LedgerMetadataInfo metadata; | |||
/** | |||
* 原来的账本设置; | |||
* | |||
* <br> | |||
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效; | |||
*/ | |||
private LedgerSettings previousSettings; | |||
private HashDigest previousSettingHash; | |||
/** | |||
* 账本的参与节点; | |||
*/ | |||
private ParticipantDataset participants; | |||
/** | |||
* “角色-权限”数据集; | |||
*/ | |||
private RolePrivilegeDataset rolePrivileges; | |||
/** | |||
* “用户-角色”数据集; | |||
*/ | |||
private UserRoleDataset userRoles; | |||
/** | |||
* 账本参数配置; | |||
*/ | |||
private LedgerSettings settings; | |||
private ExPolicyKVStorage storage; | |||
private HashDigest adminDataHash; | |||
private boolean readonly; | |||
private boolean updated; | |||
public HashDigest getHash() { | |||
return adminDataHash; | |||
} | |||
public boolean isReadonly() { | |||
return readonly; | |||
} | |||
void setReadonly() { | |||
this.readonly = true; | |||
} | |||
public LedgerSettings getPreviousSetting() { | |||
return previousSettings; | |||
} | |||
@Override | |||
public RolePrivilegeSettings getRolePrivileges() { | |||
return rolePrivileges; | |||
} | |||
@Override | |||
public UserRolesSettings getUserRoles() { | |||
return userRoles; | |||
} | |||
@Override | |||
public LedgerAdminInfo getAdminInfo() { | |||
return this; | |||
} | |||
/** | |||
* 初始化账本的管理账户; | |||
* | |||
* <br> | |||
* | |||
* 只在新建账本时调用此方法; | |||
* | |||
* @param ledgerSeed | |||
* @param settings | |||
* @param partiList | |||
* @param exPolicyStorage | |||
* @param versioningStorage | |||
*/ | |||
public LedgerAdminDataset(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
ParticipantNode[] parties = initSetting.getConsensusParticipants(); | |||
if (parties.length == 0) { | |||
throw new LedgerException("No participant!"); | |||
} | |||
// 初始化元数据; | |||
this.metadata = new LedgerMetadataInfo(); | |||
this.metadata.setSeed(initSetting.getLedgerSeed()); | |||
// 新配置; | |||
this.settings = new LedgerConfiguration(initSetting.getConsensusProvider(), initSetting.getConsensusSettings(), | |||
initSetting.getCryptoSetting()); | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = null; | |||
this.adminDataHash = null; | |||
// 基于原配置初始化参与者列表; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(previousSettings.getCryptoSetting(), partiPrefix, exPolicyStorage, | |||
versioningStorage); | |||
for (ParticipantNode p : parties) { | |||
this.participants.addConsensusParticipant(p); | |||
} | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(this.settings.getCryptoSetting(), rolePrivilegePrefix, | |||
exPolicyStorage, versioningStorage); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(this.settings.getCryptoSetting(), userRolePrefix, exPolicyStorage, | |||
versioningStorage); | |||
// 初始化其它属性; | |||
this.storage = exPolicyStorage; | |||
this.readonly = false; | |||
} | |||
public LedgerAdminDataset(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage, | |||
VersioningKVStorage versioningKVStorage, boolean readonly) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
this.storage = kvStorage; | |||
this.readonly = readonly; | |||
this.origMetadata = loadAndVerifyMetadata(adminAccountHash); | |||
this.metadata = new LedgerMetadataInfo(origMetadata); | |||
this.settings = loadAndVerifySettings(metadata.getSettingsHash()); | |||
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储; | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = metadata.getSettingsHash(); | |||
this.adminDataHash = adminAccountHash; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(metadata.getParticipantsHash(), previousSettings.getCryptoSetting(), | |||
partiPrefix, kvStorage, versioningKVStorage, readonly); | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(metadata.getRolePrivilegesHash(), | |||
previousSettings.getCryptoSetting(), rolePrivilegePrefix, kvStorage, versioningKVStorage, readonly); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(metadata.getUserRolesHash(), previousSettings.getCryptoSetting(), | |||
userRolePrefix, kvStorage, versioningKVStorage, readonly); | |||
} | |||
private LedgerSettings loadAndVerifySettings(HashDigest settingsHash) { | |||
if (settingsHash == null) { | |||
return null; | |||
} | |||
Bytes key = encodeSettingsKey(settingsHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(settingsHash.getAlgorithm()); | |||
if (!hashFunc.verify(settingsHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger setting failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeSettings(bytes); | |||
} | |||
private LedgerSettings deserializeSettings(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeSetting(LedgerSettings setting) { | |||
return BinaryProtocol.encode(setting, LedgerSettings.class); | |||
} | |||
private LedgerMetadata_V2 loadAndVerifyMetadata(HashDigest adminAccountHash) { | |||
Bytes key = encodeMetadataKey(adminAccountHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm()); | |||
if (!hashFunc.verify(adminAccountHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger metadata failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeMetadata(bytes); | |||
} | |||
private Bytes encodeSettingsKey(HashDigest settingsHash) { | |||
return settingPrefix.concat(settingsHash); | |||
} | |||
private Bytes encodeMetadataKey(HashDigest metadataHash) { | |||
// return LEDGER_META_PREFIX + metadataHash; | |||
// return metaPrefix + metadataHash; | |||
return metaPrefix.concat(metadataHash); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata() | |||
*/ | |||
@Override | |||
public LedgerMetadata_V2 getMetadata() { | |||
return metadata; | |||
} | |||
// /** | |||
// * 返回原来的账本配置; | |||
// * | |||
// * <br> | |||
// * 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSettings)} 做出了新的更改; | |||
// * | |||
// * @return | |||
// */ | |||
// public LedgerSettings getPreviousSetting() { | |||
// return previousSettings; | |||
// } | |||
/** | |||
* 返回当前设置的账本配置; | |||
* | |||
* @return | |||
*/ | |||
public LedgerSettings getSettings() { | |||
return settings; | |||
} | |||
/** | |||
* 更新账本配置; | |||
* | |||
* @param ledgerSetting | |||
*/ | |||
public void setLedgerSetting(LedgerSettings ledgerSetting) { | |||
if (readonly) { | |||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||
} | |||
settings = ledgerSetting; | |||
updated = true; | |||
} | |||
@Override | |||
public long getParticipantCount() { | |||
return participants.getParticipantCount(); | |||
} | |||
@Override | |||
public ParticipantNode[] getParticipants() { | |||
return participants.getParticipants(); | |||
} | |||
@Override | |||
public ParticipantDataset getParticipantDataset() { | |||
return participants; | |||
} | |||
/** | |||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||
* | |||
* @param participant | |||
*/ | |||
public void addParticipant(ParticipantNode participant) { | |||
participants.addConsensusParticipant(participant); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return updated || participants.isUpdated() || rolePrivileges.isUpdated() || userRoles.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
// 计算并更新参与方集合的根哈希; | |||
participants.commit(); | |||
metadata.setParticipantsHash(participants.getRootHash()); | |||
// 计算并更新角色权限集合的根哈希; | |||
rolePrivileges.commit(); | |||
metadata.setRolePrivilegesHash(rolePrivileges.getRootHash()); | |||
// 计算并更新用户角色授权集合的根哈希; | |||
userRoles.commit(); | |||
metadata.setUserRolesHash(userRoles.getRootHash()); | |||
// 当前区块上下文的密码参数设置的哈希函数; | |||
HashFunction hashFunc = Crypto.getHashFunction(previousSettings.getCryptoSetting().getHashAlgorithm()); | |||
// 计算并更新参数配置的哈希; | |||
if (settings == null) { | |||
throw new LedgerException("Missing ledger settings!"); | |||
} | |||
byte[] settingsBytes = serializeSetting(settings); | |||
HashDigest settingsHash = hashFunc.hash(settingsBytes); | |||
metadata.setSettingsHash(settingsHash); | |||
if (previousSettingHash == null || !previousSettingHash.equals(settingsHash)) { | |||
Bytes settingsKey = encodeSettingsKey(settingsHash); | |||
boolean nx = storage.set(settingsKey, settingsBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = settingsHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
} | |||
// 基于之前的密码配置来计算元数据的哈希; | |||
byte[] metadataBytes = serializeMetadata(metadata); | |||
HashDigest metadataHash = hashFunc.hash(metadataBytes); | |||
if (adminDataHash == null || !adminDataHash.equals(metadataHash)) { | |||
// update modify; | |||
// String base58MetadataHash = metadataHash.toBase58(); | |||
// String metadataKey = encodeMetadataKey(base58MetadataHash); | |||
Bytes metadataKey = encodeMetadataKey(metadataHash); | |||
boolean nx = storage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = metadataHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
adminDataHash = metadataHash; | |||
} | |||
updated = false; | |||
} | |||
private LedgerMetadata_V2 deserializeMetadata(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeMetadata(LedgerMetadataInfo config) { | |||
return BinaryProtocol.encode(config, LedgerMetadata_V2.class); | |||
} | |||
@Override | |||
public void cancel() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
participants.cancel(); | |||
metadata =origMetadata == null ? new LedgerMetadataInfo() : new LedgerMetadataInfo(origMetadata); | |||
} | |||
public static class LedgerMetadataInfo implements LedgerMetadata_V2 { | |||
private byte[] seed; | |||
// private LedgerSetting setting; | |||
private HashDigest participantsHash; | |||
private HashDigest settingsHash; | |||
private HashDigest rolePrivilegesHash; | |||
private HashDigest userRolesHash; | |||
public LedgerMetadataInfo() { | |||
} | |||
public LedgerMetadataInfo(LedgerMetadata_V2 metadata) { | |||
this.seed = metadata.getSeed(); | |||
this.participantsHash = metadata.getParticipantsHash(); | |||
this.settingsHash = metadata.getSettingsHash(); | |||
this.rolePrivilegesHash = metadata.getRolePrivilegesHash(); | |||
this.userRolesHash = metadata.getUserRolesHash(); | |||
} | |||
@Override | |||
public byte[] getSeed() { | |||
return seed; | |||
} | |||
@Override | |||
public HashDigest getSettingsHash() { | |||
return settingsHash; | |||
} | |||
@Override | |||
public HashDigest getParticipantsHash() { | |||
return participantsHash; | |||
} | |||
@Override | |||
public HashDigest getRolePrivilegesHash() { | |||
return rolePrivilegesHash; | |||
} | |||
@Override | |||
public HashDigest getUserRolesHash() { | |||
return userRolesHash; | |||
} | |||
public void setSeed(byte[] seed) { | |||
this.seed = seed; | |||
} | |||
public void setSettingsHash(HashDigest settingHash) { | |||
this.settingsHash = settingHash; | |||
} | |||
public void setParticipantsHash(HashDigest participantsHash) { | |||
this.participantsHash = participantsHash; | |||
} | |||
public void setRolePrivilegesHash(HashDigest rolePrivilegesHash) { | |||
this.rolePrivilegesHash = rolePrivilegesHash; | |||
} | |||
public void setUserRolesHash(HashDigest userRolesHash) { | |||
this.userRolesHash = userRolesHash; | |||
} | |||
} | |||
} |
@@ -1,5 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
public enum LedgerAdminPrivilege { | |||
} |
@@ -1,16 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
public interface LedgerAdministration { | |||
LedgerMetadata getMetadata(); | |||
long getParticipantCount(); | |||
// ParticipantNode getParticipant(int id); | |||
ParticipantNode[] getParticipants(); | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; |
@@ -1,10 +1,10 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerSetting; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class LedgerConfiguration implements LedgerSetting { | |||
public class LedgerConfiguration implements LedgerSettings { | |||
private String consensusProvider; | |||
@@ -16,7 +16,7 @@ public class LedgerConfiguration implements LedgerSetting { | |||
this.cryptoSetting = new CryptoConfig(); | |||
} | |||
public LedgerConfiguration(LedgerSetting origSetting) { | |||
public LedgerConfiguration(LedgerSettings origSetting) { | |||
if (origSetting != null) { | |||
this.consensusProvider = origSetting.getConsensusProvider(); | |||
this.consensusSetting = origSetting.getConsensusSetting(); | |||
@@ -0,0 +1,19 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* {@link LedgerDataset} 表示账本在某一个区块上的数据集合; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface LedgerDataQuery{ | |||
LedgerAdminDataQuery getAdminDataset(); | |||
UserAccountQuery getUserAccountSet(); | |||
DataAccountQuery getDataAccountSet(); | |||
ContractAccountQuery getContractAccountset(); | |||
} |
@@ -1,21 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* {@link LedgerDataSet} 表示账本在某一个区块上的数据集合; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface LedgerDataSet{ | |||
boolean isReadonly(); | |||
LedgerAdminAccount getAdminAccount(); | |||
UserAccountSet getUserAccountSet(); | |||
DataAccountSet getDataAccountSet(); | |||
ContractAccountSet getContractAccountSet(); | |||
} |
@@ -1,33 +1,31 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.core.*; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||
public class LedgerDataset implements LedgerDataQuery, Transactional { | |||
private LedgerAdminAccount adminAccount; | |||
private LedgerAdminDataset adminDataset; | |||
private UserAccountSet userAccountSet; | |||
private DataAccountSet dataAccountSet; | |||
private ContractAccountSet contractAccountSet; | |||
private boolean readonly; | |||
private boolean readonly; | |||
/** | |||
* Create new block; | |||
* | |||
* @param adminAccount | |||
* @param userAccountSet | |||
* @param dataAccountSet | |||
* @param contractAccountSet | |||
* @param readonly | |||
*/ | |||
public LedgerDataSetImpl(LedgerAdminAccount adminAccount, | |||
UserAccountSet userAccountSet, DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet, | |||
boolean readonly) { | |||
this.adminAccount = adminAccount; | |||
public LedgerDataset(LedgerAdminDataset adminAccount, UserAccountSet userAccountSet, | |||
DataAccountSet dataAccountSet, ContractAccountSet contractAccountSet, boolean readonly) { | |||
this.adminDataset = adminAccount; | |||
this.userAccountSet = userAccountSet; | |||
this.dataAccountSet = dataAccountSet; | |||
this.contractAccountSet = contractAccountSet; | |||
@@ -36,8 +34,8 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||
} | |||
@Override | |||
public LedgerAdminAccount getAdminAccount() { | |||
return adminAccount; | |||
public LedgerAdminDataset getAdminDataset() { | |||
return adminDataset; | |||
} | |||
@Override | |||
@@ -51,13 +49,13 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||
} | |||
@Override | |||
public ContractAccountSet getContractAccountSet() { | |||
public ContractAccountSet getContractAccountset() { | |||
return contractAccountSet; | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return adminAccount.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated() | |||
return adminDataset.isUpdated() || userAccountSet.isUpdated() || dataAccountSet.isUpdated() | |||
|| contractAccountSet.isUpdated(); | |||
} | |||
@@ -70,7 +68,7 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||
return; | |||
} | |||
adminAccount.commit(); | |||
adminDataset.commit(); | |||
userAccountSet.commit(); | |||
dataAccountSet.commit(); | |||
contractAccountSet.commit(); | |||
@@ -78,15 +76,22 @@ public class LedgerDataSetImpl implements LedgerDataSet, Transactional { | |||
@Override | |||
public void cancel() { | |||
adminAccount.cancel(); | |||
adminDataset.cancel(); | |||
userAccountSet.cancel(); | |||
dataAccountSet.cancel(); | |||
contractAccountSet.cancel(); | |||
} | |||
@Override | |||
public boolean isReadonly() { | |||
return readonly; | |||
} | |||
void setReadonly() { | |||
this.readonly = true; | |||
this.adminDataset.setReadonly(); | |||
this.userAccountSet.setReadonly(); | |||
this.dataAccountSet.setReadonly(); | |||
this.contractAccountSet.setReadonly(); | |||
} | |||
} |
@@ -11,7 +11,7 @@ import com.jd.blockchain.ledger.TransactionRequest; | |||
* <p> | |||
* | |||
* {@link LedgerEditor} 以上一个区块作为数据编辑的起点; <br> | |||
* 对账本数据({@link #getDataSet()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点; | |||
* 对账本数据({@link #getDataset()})的批量更改可以作为一个交易({@link LedgerTransaction})整体提交暂存,形成暂存点; | |||
* <br> | |||
* | |||
* @author huanghaiquan | |||
@@ -33,11 +33,25 @@ public interface LedgerEditor { | |||
*/ | |||
long getBlockHeight(); | |||
/** | |||
* 最新的账本数据集; | |||
* | |||
* @return | |||
*/ | |||
LedgerDataset getLedgerDataset(); | |||
/** | |||
* 最新的交易集合; | |||
* | |||
* @return | |||
*/ | |||
TransactionSet getTransactionSet(); | |||
/** | |||
* 开始新事务;<br> | |||
* | |||
* 方法返回之前,将会校验交易请求的用户签名列表和节点签名列表,并在后续对数据集 | |||
* {@link LedgerTransactionContext#getDataSet()} 的操作时,校验这些用户和节点是否具备权限;<br> | |||
* {@link LedgerTransactionContext#getDataset()} 的操作时,校验这些用户和节点是否具备权限;<br> | |||
* | |||
* 校验失败将引发异常 {@link LedgerException}; | |||
* <p> | |||
@@ -52,7 +66,8 @@ public interface LedgerEditor { | |||
* | |||
* | |||
* | |||
* 注:方法不解析、不执行交易中的操作;<p> | |||
* 注:方法不解析、不执行交易中的操作; | |||
* <p> | |||
* | |||
* @param txRequest 交易请求; | |||
* @return | |||
@@ -13,8 +13,8 @@ import com.jd.blockchain.ledger.LedgerInitOperation; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.METADATA_INIT_PERMISSION) | |||
public interface LedgerInitPermission { | |||
@DataContract(code = DataCodes.METADATA_INIT_PROPOSAL) | |||
public interface LedgerInitProposal { | |||
/** | |||
* 做出许可的参与方 ID; |
@@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
public class LedgerInitPermissionData implements LedgerInitPermission { | |||
public class LedgerInitProposalData implements LedgerInitProposal { | |||
private int participantId; | |||
@@ -11,10 +11,11 @@ public class LedgerInitPermissionData implements LedgerInitPermission { | |||
/** | |||
* a private contructor for deserialize; | |||
*/ | |||
private LedgerInitPermissionData() { | |||
@SuppressWarnings("unused") | |||
private LedgerInitProposalData() { | |||
} | |||
public LedgerInitPermissionData(int participantId, SignatureDigest initTxSignature) { | |||
public LedgerInitProposalData(int participantId, SignatureDigest initTxSignature) { | |||
this.participantId = participantId; | |||
this.transactionSignature = initTxSignature; | |||
} |
@@ -0,0 +1,215 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInitException; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.RoleInitSettings; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||
import com.jd.blockchain.ledger.SecurityInitSettings; | |||
import com.jd.blockchain.ledger.TransactionBuilder; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.UserAuthInitSettings; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.service.TransactionBatchResultHandle; | |||
import com.jd.blockchain.storage.service.KVStorageService; | |||
import com.jd.blockchain.transaction.SignatureUtils; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.transaction.TxRequestBuilder; | |||
public class LedgerInitializer { | |||
private static final FullPermissionedSecurityManager FULL_PERMISSION_SECURITY_MANAGER = new FullPermissionedSecurityManager(); | |||
private static final LedgerDataQuery EMPTY_LEDGER_DATA_QUERY = new EmptyLedgerDataset(); | |||
private static final OperationHandleRegisteration DEFAULT_OP_HANDLE_REG = new DefaultOperationHandleRegisteration(); | |||
private LedgerService EMPTY_LEDGERS = new LedgerManager(); | |||
private LedgerInitSetting initSetting; | |||
private TransactionContent initTxContent; | |||
private volatile LedgerBlock genesisBlock; | |||
private volatile LedgerEditor ledgerEditor; | |||
private volatile boolean committed = false; | |||
private volatile boolean canceled = false; | |||
private TransactionBatchResultHandle txResultsHandle; | |||
/** | |||
* 初始化生成的账本hash; <br> | |||
* | |||
* 在成功执行 {@link #prepareLedger(KVStorageService, DigitalSignature...)} 之前总是返回 | |||
* null; | |||
* | |||
* @return | |||
*/ | |||
public HashDigest getLedgerHash() { | |||
return genesisBlock == null ? null : genesisBlock.getHash(); | |||
} | |||
/** | |||
* @param initSetting | |||
* @param initTxContent | |||
*/ | |||
private LedgerInitializer(LedgerInitSetting initSetting, TransactionContent initTxContent) { | |||
this.initSetting = initSetting; | |||
this.initTxContent = initTxContent; | |||
} | |||
public TransactionContent getTransactionContent() { | |||
return initTxContent; | |||
} | |||
private static SecurityInitSettings createDefaultSecurityInitSettings() { | |||
// TODO throw new IllegalStateException("Not implemented!"); | |||
return null; | |||
} | |||
// public static LedgerInitializer create(LedgerInitSetting initSetting) { | |||
// return create(initSetting, createDefaultSecurityInitSettings()); | |||
// } | |||
public static LedgerInitializer create(LedgerInitSetting initSetting, SecurityInitSettings securityInitSettings) { | |||
// 生成创世交易; | |||
TransactionContent initTxContent = buildGenesisTransaction(initSetting, securityInitSettings); | |||
return new LedgerInitializer(initSetting, initTxContent); | |||
} | |||
/** | |||
* 根据初始化配置,生成创始交易; | |||
* <p> | |||
* | |||
* “创世交易”按顺序由以下操作组成:<br> | |||
* (1) 账本初始化 {@link LedgerInitOperation}:此操作仅用于锚定了原始的交易配置,对应的 | |||
* {@link OperationHandle} 执行空操作,由“创世交易”其余的操作来表达对账本的实际修改;<br> | |||
* (2) 注册用户 {@link UserRegisterOperation}:有一项或者多项;<br> | |||
* (3) 配置角色 {@link RolesConfigureOperation}:有一项或者多项;<br> | |||
* (4) 授权用户 {@link UserAuthorizeOperation}:有一项或者多项;<br> | |||
* | |||
* @param initSetting | |||
* @param securityInitSettings | |||
* @return | |||
*/ | |||
public static TransactionContent buildGenesisTransaction(LedgerInitSetting initSetting, | |||
SecurityInitSettings securityInitSettings) { | |||
// 账本初始化交易的账本 hash 为 null; | |||
TransactionBuilder initTxBuilder = new TxBuilder(null); | |||
// 定义账本初始化操作; | |||
initTxBuilder.ledgers().create(initSetting); | |||
// TODO: 注册参与方; 目前由 LedgerInitSetting 定义,在 LedgerAdminDataset 中解释执行; | |||
// 注册用户; | |||
for (ParticipantNode p : initSetting.getConsensusParticipants()) { | |||
// TODO:暂时只支持注册用户的初始化操作; | |||
BlockchainIdentity superUserId = new BlockchainIdentityData(p.getPubKey()); | |||
initTxBuilder.users().register(superUserId); | |||
} | |||
// 配置角色; | |||
for (RoleInitSettings roleSettings : securityInitSettings.getRoles()) { | |||
initTxBuilder.security().roles().configure(roleSettings.getRoleName()) | |||
.enable(roleSettings.getLedgerPermissions()).enable(roleSettings.getTransactionPermissions()); | |||
} | |||
// 授权用户; | |||
for (UserAuthInitSettings userAuthSettings : securityInitSettings.getUserAuthorizations()) { | |||
initTxBuilder.security().authorziations().forUser(userAuthSettings.getUserAddress()) | |||
.authorize(userAuthSettings.getRoles()) | |||
.setPolicy(userAuthSettings.getPolicy()); | |||
} | |||
// 账本初始化配置声明的创建时间来初始化交易时间戳;注:不能用本地时间,因为共识节点之间的本地时间系统不一致; | |||
return initTxBuilder.prepareContent(initSetting.getCreatedTime()); | |||
} | |||
public SignatureDigest signTransaction(PrivKey privKey) { | |||
return SignatureUtils.sign(initTxContent, privKey); | |||
} | |||
/** | |||
* 准备创建账本; | |||
* | |||
* @param storageService 存储服务; | |||
* @param nodeSignatures 节点签名列表; | |||
* @return | |||
*/ | |||
public LedgerBlock prepareLedger(KVStorageService storageService, DigitalSignature... nodeSignatures) { | |||
if (genesisBlock != null) { | |||
throw new LedgerInitException("The ledger has been prepared!"); | |||
} | |||
// 生成账本; | |||
this.ledgerEditor = createLedgerEditor(this.initSetting, storageService); | |||
this.genesisBlock = prepareLedger(ledgerEditor, nodeSignatures); | |||
return genesisBlock; | |||
} | |||
public void commit() { | |||
if (committed) { | |||
throw new LedgerInitException("The ledger has been committed!"); | |||
} | |||
if (canceled) { | |||
throw new LedgerInitException("The ledger has been canceled!"); | |||
} | |||
committed = true; | |||
this.txResultsHandle.commit(); | |||
} | |||
public void cancel() { | |||
if (canceled) { | |||
throw new LedgerInitException("The ledger has been canceled!"); | |||
} | |||
if (committed) { | |||
throw new LedgerInitException("The ledger has been committed!"); | |||
} | |||
this.ledgerEditor.cancel(); | |||
} | |||
public static LedgerEditor createLedgerEditor(LedgerInitSetting initSetting, KVStorageService storageService) { | |||
LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, | |||
LedgerManage.LEDGER_PREFIX, storageService.getExPolicyKVStorage(), | |||
storageService.getVersioningKVStorage()); | |||
return genesisBlockEditor; | |||
} | |||
/** | |||
* 初始化账本数据,返回创始区块; | |||
* | |||
* @param ledgerEditor | |||
* @return | |||
*/ | |||
private LedgerBlock prepareLedger(LedgerEditor ledgerEditor, DigitalSignature... nodeSignatures) { | |||
// 初始化时,自动将参与方注册为账本的用户; | |||
TxRequestBuilder txReqBuilder = new TxRequestBuilder(this.initTxContent); | |||
txReqBuilder.addNodeSignature(nodeSignatures); | |||
TransactionRequest txRequest = txReqBuilder.buildRequest(); | |||
TransactionBatchProcessor txProcessor = new TransactionBatchProcessor(FULL_PERMISSION_SECURITY_MANAGER, | |||
ledgerEditor, EMPTY_LEDGER_DATA_QUERY, DEFAULT_OP_HANDLE_REG, EMPTY_LEDGERS); | |||
txProcessor.schedule(txRequest); | |||
txResultsHandle = txProcessor.prepare(); | |||
return txResultsHandle.getBlock(); | |||
} | |||
} |
@@ -12,19 +12,21 @@ import com.jd.blockchain.storage.service.KVStorageService; | |||
*/ | |||
public interface LedgerManage extends LedgerService { | |||
static final String LEDGER_PREFIX = "LDG://"; | |||
LedgerRepository register(HashDigest ledgerHash, KVStorageService storageService); | |||
void unregister(HashDigest ledgerHash); | |||
/** | |||
* 创建新账本; | |||
* | |||
* @param initSetting | |||
* 初始化配置; | |||
* @param initPermissions | |||
* 参与者的初始化授权列表;与参与者列表一致; | |||
* @return | |||
*/ | |||
LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService); | |||
// /** | |||
// * 创建新账本; | |||
// * | |||
// * @param initSetting | |||
// * 初始化配置; | |||
// * @param initPermissions | |||
// * 参与者的初始化授权列表;与参与者列表一致; | |||
// * @return | |||
// */ | |||
// LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService); | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
@@ -9,11 +9,6 @@ import com.jd.blockchain.crypto.CryptoProvider; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.core.LedgerConsts; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerManage; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.KVStorageService; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
@@ -27,8 +22,6 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||
*/ | |||
public class LedgerManager implements LedgerManage { | |||
private static final String LEDGER_PREFIX = "LDG://"; | |||
// @Autowired | |||
// private ExistentialKVStorage exPolicyStorage; | |||
// | |||
@@ -69,7 +62,7 @@ public class LedgerManager implements LedgerManage { | |||
ledgerVersioningStorage); | |||
// 校验 crypto service provider ; | |||
CryptoSetting cryptoSetting = ledgerRepo.getAdminAccount().getSetting().getCryptoSetting(); | |||
CryptoSetting cryptoSetting = ledgerRepo.getAdminInfo().getSettings().getCryptoSetting(); | |||
checkCryptoSetting(cryptoSetting, ledgerHash); | |||
// 创建账本上下文; | |||
@@ -142,18 +135,18 @@ public class LedgerManager implements LedgerManage { | |||
} | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.LedgerManager#newLedger(com.jd.blockchain. | |||
* ledger.core.ConsensusConfig, com.jd.blockchain.ledger.core.CryptoConfig) | |||
*/ | |||
@Override | |||
public LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService) { | |||
LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_PREFIX, | |||
storageService.getExPolicyKVStorage(), storageService.getVersioningKVStorage()); | |||
return genesisBlockEditor; | |||
} | |||
// /* | |||
// * (non-Javadoc) | |||
// * | |||
// * @see com.jd.blockchain.ledger.core.LedgerManager#newLedger(com.jd.blockchain. | |||
// * ledger.core.ConsensusConfig, com.jd.blockchain.ledger.core.CryptoConfig) | |||
// */ | |||
// @Override | |||
// public LedgerEditor newLedger(LedgerInitSetting initSetting, KVStorageService storageService) { | |||
// LedgerEditor genesisBlockEditor = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_PREFIX, | |||
// storageService.getExPolicyKVStorage(), storageService.getVersioningKVStorage()); | |||
// return genesisBlockEditor; | |||
// } | |||
static String getLedgerStoragePrefix(HashDigest ledgerHash) { | |||
String base58LedgerHash = Base58Utils.encode(ledgerHash.toBytes()); |
@@ -1,19 +1,25 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.DataAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerAdministration; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.TransactionSet; | |||
import com.jd.blockchain.ledger.core.UserAccountSet; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.KVDataObject; | |||
import com.jd.blockchain.ledger.KVDataVO; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.transaction.BlockchainQueryService; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.QueryUtil; | |||
@@ -42,15 +48,23 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); | |||
return ledgerInfo; | |||
} | |||
@Override | |||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
LedgerAdminInfo administration = ledger.getAdminInfo(block); | |||
return administration; | |||
} | |||
@Override | |||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | |||
return ledgerAdministration(ledgerHash).getParticipants(); | |||
return getLedgerAdminInfo(ledgerHash).getParticipants(); | |||
} | |||
@Override | |||
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | |||
return ledgerAdministration(ledgerHash).getMetadata(); | |||
return getLedgerAdminInfo(ledgerHash).getMetadata(); | |||
} | |||
@Override | |||
@@ -93,7 +107,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getDataAccountCount(HashDigest ledgerHash, long height) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(height); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getTotalCount(); | |||
} | |||
@@ -101,7 +115,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(blockHash); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getTotalCount(); | |||
} | |||
@@ -109,7 +123,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getDataAccountTotalCount(HashDigest ledgerHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getTotalCount(); | |||
} | |||
@@ -117,7 +131,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getUserCount(HashDigest ledgerHash, long height) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(height); | |||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
return userAccountSet.getTotalCount(); | |||
} | |||
@@ -125,7 +139,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(blockHash); | |||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
return userAccountSet.getTotalCount(); | |||
} | |||
@@ -133,7 +147,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getUserTotalCount(HashDigest ledgerHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
return userAccountSet.getTotalCount(); | |||
} | |||
@@ -141,7 +155,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getContractCount(HashDigest ledgerHash, long height) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(height); | |||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
return contractAccountSet.getTotalCount(); | |||
} | |||
@@ -149,7 +163,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getBlock(blockHash); | |||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
return contractAccountSet.getTotalCount(); | |||
} | |||
@@ -157,7 +171,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public long getContractTotalCount(HashDigest ledgerHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
return contractAccountSet.getTotalCount(); | |||
} | |||
@@ -240,7 +254,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public UserInfo getUser(HashDigest ledgerHash, String address) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
return userAccountSet.getUser(address); | |||
} | |||
@@ -249,7 +263,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
} | |||
@@ -260,7 +274,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
@@ -308,7 +322,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
@@ -339,7 +353,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); | |||
@@ -351,7 +365,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); | |||
return dataAccount.getDataEntriesTotalCount(); | |||
@@ -361,7 +375,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
return contractAccountSet.getContract(Bytes.fromBase58(address)); | |||
} | |||
@@ -369,7 +383,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
UserAccountSet userAccountSet = ledger.getUserAccountSet(block); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); | |||
return userAccountSet.getAccounts(pages[0], pages[1]); | |||
} | |||
@@ -378,7 +392,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); | |||
return dataAccountSet.getAccounts(pages[0], pages[1]); | |||
} | |||
@@ -387,15 +401,9 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); | |||
return contractAccountSet.getAccounts(pages[0], pages[1]); | |||
} | |||
private LedgerAdministration ledgerAdministration(HashDigest ledgerHash) { | |||
LedgerRepository ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
LedgerAdministration administration = ledger.getAdminAccount(block); | |||
return administration; | |||
} | |||
} |
@@ -3,6 +3,7 @@ package com.jd.blockchain.ledger.core; | |||
import java.io.Closeable; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
public interface LedgerRepository extends Closeable { | |||
@@ -51,23 +52,23 @@ public interface LedgerRepository extends Closeable { | |||
*/ | |||
LedgerBlock getBlock(long height); | |||
LedgerAdministration getAdminInfo(); | |||
LedgerAdminInfo getAdminInfo(); | |||
LedgerAdminInfo getAdminInfo(LedgerBlock block); | |||
LedgerBlock getBlock(HashDigest hash); | |||
LedgerDataSet getDataSet(LedgerBlock block); | |||
LedgerDataQuery getDataSet(LedgerBlock block); | |||
TransactionSet getTransactionSet(LedgerBlock block); | |||
LedgerAdminAccount getAdminAccount(LedgerBlock block); | |||
UserAccountQuery getUserAccountSet(LedgerBlock block); | |||
UserAccountSet getUserAccountSet(LedgerBlock block); | |||
DataAccountQuery getDataAccountSet(LedgerBlock block); | |||
DataAccountSet getDataAccountSet(LedgerBlock block); | |||
ContractAccountQuery getContractAccountSet(LedgerBlock block); | |||
ContractAccountSet getContractAccountSet(LedgerBlock block); | |||
default LedgerDataSet getDataSet() { | |||
default LedgerDataQuery getDataSet() { | |||
return getDataSet(getLatestBlock()); | |||
} | |||
@@ -75,19 +76,15 @@ public interface LedgerRepository extends Closeable { | |||
return getTransactionSet(getLatestBlock()); | |||
} | |||
default LedgerAdminAccount getAdminAccount() { | |||
return getAdminAccount(getLatestBlock()); | |||
} | |||
default UserAccountSet getUserAccountSet() { | |||
default UserAccountQuery getUserAccountSet() { | |||
return getUserAccountSet(getLatestBlock()); | |||
} | |||
default DataAccountSet getDataAccountSet() { | |||
default DataAccountQuery getDataAccountSet() { | |||
return getDataAccountSet(getLatestBlock()); | |||
} | |||
default ContractAccountSet getContractAccountSet() { | |||
default ContractAccountQuery getContractAccountSet() { | |||
return getContractAccountSet(getLatestBlock()); | |||
} | |||
@@ -1,23 +1,17 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.ledger.core.AccountAccessPolicy; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.DataAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerAdminAccount; | |||
import com.jd.blockchain.ledger.core.LedgerAdministration; | |||
import com.jd.blockchain.ledger.core.LedgerConsts; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.ledger.core.SettingContext; | |||
import com.jd.blockchain.ledger.core.TransactionSet; | |||
import com.jd.blockchain.ledger.core.UserAccountSet; | |||
import com.jd.blockchain.ledger.BlockBody; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -36,7 +30,7 @@ import com.jd.blockchain.utils.codec.Base58Utils; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerRepositoryImpl implements LedgerRepository { | |||
class LedgerRepositoryImpl implements LedgerRepository { | |||
private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); | |||
@@ -80,6 +74,8 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
if (getLatestBlockHeight() < 0) { | |||
throw new RuntimeException("Ledger doesn't exist!"); | |||
} | |||
retrieveLatestState(); | |||
} | |||
/* | |||
@@ -110,25 +106,27 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
@Override | |||
public LedgerBlock getLatestBlock() { | |||
LedgerState state = getLatestState(); | |||
return state.block; | |||
return latestState.block; | |||
} | |||
private LedgerState getLatestState() { | |||
LedgerState state = latestState; | |||
if (state == null) { | |||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||
state = new LedgerState(latestBlock); | |||
latestState = state; | |||
} | |||
return state; | |||
/** | |||
* 重新检索加载最新的状态; | |||
* | |||
* @return | |||
*/ | |||
private LedgerState retrieveLatestState() { | |||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||
LedgerDataset ledgerDataset = innerGetLedgerDataset(latestBlock); | |||
TransactionSet txSet = loadTransactionSet(latestBlock.getTransactionSetHash(), | |||
ledgerDataset.getAdminDataset().getSettings().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
this.latestState = new LedgerState(latestBlock, ledgerDataset, txSet); | |||
return latestState; | |||
} | |||
@Override | |||
public LedgerBlock retrieveLatestBlock() { | |||
LedgerBlock latestBlock = innerGetBlock(innerGetLatestBlockHeight()); | |||
latestState = new LedgerState(latestBlock); | |||
return latestBlock; | |||
return retrieveLatestState().block; | |||
} | |||
@Override | |||
@@ -187,7 +185,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
if (height < 0) { | |||
return null; | |||
} | |||
return innerGetBlock(getBlockHash(height)); | |||
return innerGetBlock(innerGetBlockHash(height)); | |||
} | |||
@Override | |||
@@ -209,26 +207,18 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
throw new RuntimeException("Block hash not equals to it's storage key!"); | |||
} | |||
// verify hash; | |||
// boolean requiredVerifyHash = | |||
// adminAccount.getMetadata().getSetting().getCryptoSetting().getAutoVerifyHash(); | |||
// TODO: 未实现从配置中加载是否校验 Hash 的设置; | |||
if (SettingContext.queryingSettings().verifyHash()) { | |||
byte[] blockBodyBytes = null; | |||
if (block.getHeight() == 0) { | |||
// 计算创世区块的 hash 时,不包括 ledgerHash 字段; | |||
block.setLedgerHash(null); | |||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||
// 恢复; | |||
block.setLedgerHash(block.getHash()); | |||
} else { | |||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||
} | |||
HashFunction hashFunc = Crypto.getHashFunction(blockHash.getAlgorithm()); | |||
boolean pass = hashFunc.verify(blockHash, blockBodyBytes); | |||
if (!pass) { | |||
throw new RuntimeException("Block hash verification fail!"); | |||
} | |||
// verify block hash; | |||
byte[] blockBodyBytes = null; | |||
if (block.getHeight() == 0) { | |||
// 计算创世区块的 hash 时,不包括 ledgerHash 字段; | |||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||
} else { | |||
blockBodyBytes = BinaryProtocol.encode(block, BlockBody.class); | |||
} | |||
HashFunction hashFunc = Crypto.getHashFunction(blockHash.getAlgorithm()); | |||
boolean pass = hashFunc.verify(blockHash, blockBodyBytes); | |||
if (!pass) { | |||
throw new RuntimeException("Block hash verification fail!"); | |||
} | |||
// verify height; | |||
@@ -243,9 +233,18 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
return block; | |||
} | |||
/** | |||
* 获取最新区块的账本参数; | |||
* | |||
* @return | |||
*/ | |||
private LedgerSettings getLatestSettings() { | |||
return getAdminInfo().getSettings(); | |||
} | |||
@Override | |||
public LedgerAdministration getAdminInfo() { | |||
return getAdminAccount(getLatestBlock()); | |||
public LedgerAdminInfo getAdminInfo() { | |||
return getAdminInfo(getLatestBlock()); | |||
} | |||
private LedgerBlock deserialize(byte[] blockBytes) { | |||
@@ -255,140 +254,96 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
@Override | |||
public TransactionSet getTransactionSet(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
TransactionSet transactionSet = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
transactionSet = state.transactionSet; | |||
if (transactionSet == null) { | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
transactionSet = loadTransactionSet(block.getTransactionSetHash(), | |||
adminAccount.getMetadata().getSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
state.transactionSet = transactionSet; | |||
} | |||
return transactionSet; | |||
// 从缓存中返回最新区块的数据集; | |||
return latestState.getTransactionSet(); | |||
} | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
LedgerAdminInfo adminAccount = getAdminInfo(block); | |||
// All of existing block is readonly; | |||
return loadTransactionSet(block.getTransactionSetHash(), | |||
adminAccount.getMetadata().getSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
return loadTransactionSet(block.getTransactionSetHash(), adminAccount.getSettings().getCryptoSetting(), | |||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||
} | |||
@Override | |||
public LedgerAdminAccount getAdminAccount(LedgerBlock block) { | |||
public LedgerAdminDataset getAdminInfo(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
LedgerAdminAccount adminAccount = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
adminAccount = state.adminAccount; | |||
if (adminAccount == null) { | |||
adminAccount = new LedgerAdminAccount(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
state.adminAccount = adminAccount; | |||
} | |||
return adminAccount; | |||
return latestState.getAdminDataset(); | |||
} | |||
return new LedgerAdminAccount(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, versioningStorage, true); | |||
return createAdminDataset(block); | |||
} | |||
private LedgerAdminDataset createAdminDataset(LedgerBlock block) { | |||
return new LedgerAdminDataset(block.getAdminAccountHash(), keyPrefix, exPolicyStorage, versioningStorage, true); | |||
} | |||
@Override | |||
public UserAccountSet getUserAccountSet(LedgerBlock block) { | |||
public UserAccountQuery getUserAccountSet(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
UserAccountSet userAccountSet = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
userAccountSet = state.userAccountSet; | |||
if (userAccountSet == null) { | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
userAccountSet = loadUserAccountSet(block.getUserAccountSetHash(), | |||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
state.userAccountSet = userAccountSet; | |||
} | |||
return userAccountSet; | |||
return latestState.getUserAccountSet(); | |||
} | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
return loadUserAccountSet(block.getUserAccountSetHash(), adminAccount.getPreviousSetting().getCryptoSetting(), | |||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||
return createUserAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||
} | |||
private UserAccountSet createUserAccountSet(LedgerBlock block, CryptoSetting cryptoSetting) { | |||
return loadUserAccountSet(block.getUserAccountSetHash(), cryptoSetting, keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
} | |||
@Override | |||
public DataAccountSet getDataAccountSet(LedgerBlock block) { | |||
public DataAccountQuery getDataAccountSet(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
DataAccountSet dataAccountSet = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
dataAccountSet = state.dataAccountSet; | |||
if (dataAccountSet == null) { | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
dataAccountSet = loadDataAccountSet(block.getDataAccountSetHash(), | |||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
state.dataAccountSet = dataAccountSet; | |||
} | |||
return dataAccountSet; | |||
return latestState.getDataAccountSet(); | |||
} | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
return loadDataAccountSet(block.getDataAccountSetHash(), adminAccount.getPreviousSetting().getCryptoSetting(), | |||
keyPrefix, exPolicyStorage, versioningStorage, true); | |||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||
return createDataAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||
} | |||
private DataAccountSet createDataAccountSet(LedgerBlock block, CryptoSetting setting) { | |||
return loadDataAccountSet(block.getDataAccountSetHash(), setting, keyPrefix, exPolicyStorage, versioningStorage, | |||
true); | |||
} | |||
@Override | |||
public ContractAccountSet getContractAccountSet(LedgerBlock block) { | |||
public ContractAccountQuery getContractAccountSet(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
ContractAccountSet contractAccountSet = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
contractAccountSet = state.contractAccountSet; | |||
if (contractAccountSet == null) { | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
contractAccountSet = loadContractAccountSet(block.getContractAccountSetHash(), | |||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
state.contractAccountSet = contractAccountSet; | |||
} | |||
return contractAccountSet; | |||
return latestState.getContractAccountSet(); | |||
} | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
return loadContractAccountSet(block.getContractAccountSetHash(), | |||
adminAccount.getPreviousSetting().getCryptoSetting(), keyPrefix, exPolicyStorage, versioningStorage, | |||
true); | |||
LedgerAdminDataset adminAccount = getAdminInfo(block); | |||
return createContractAccountSet(block, adminAccount.getSettings().getCryptoSetting()); | |||
} | |||
private ContractAccountSet createContractAccountSet(LedgerBlock block, CryptoSetting cryptoSetting) { | |||
return loadContractAccountSet(block.getContractAccountSetHash(), cryptoSetting, keyPrefix, exPolicyStorage, | |||
versioningStorage, true); | |||
} | |||
@Override | |||
public LedgerDataSet getDataSet(LedgerBlock block) { | |||
public LedgerDataset getDataSet(LedgerBlock block) { | |||
long height = getLatestBlockHeight(); | |||
LedgerDataSet ledgerDataSet = null; | |||
if (height == block.getHeight()) { | |||
// 缓存读; | |||
LedgerState state = getLatestState(); | |||
ledgerDataSet = state.ledgerDataSet; | |||
if (ledgerDataSet == null) { | |||
ledgerDataSet = innerDataSet(block); | |||
state.ledgerDataSet = ledgerDataSet; | |||
} | |||
return ledgerDataSet; | |||
return latestState.getLedgerDataset(); | |||
} | |||
// All of existing block is readonly; | |||
return innerDataSet(block); | |||
return innerGetLedgerDataset(block); | |||
} | |||
private LedgerDataSet innerDataSet(LedgerBlock block) { | |||
LedgerAdminAccount adminAccount = getAdminAccount(block); | |||
UserAccountSet userAccountSet = getUserAccountSet(block); | |||
DataAccountSet dataAccountSet = getDataAccountSet(block); | |||
ContractAccountSet contractAccountSet = getContractAccountSet(block); | |||
return new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, contractAccountSet, true); | |||
private LedgerDataset innerGetLedgerDataset(LedgerBlock block) { | |||
LedgerAdminDataset adminDataset = createAdminDataset(block); | |||
CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); | |||
UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); | |||
DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); | |||
ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); | |||
return new LedgerDataset(adminDataset, userAccountSet, dataAccountSet, contractAccountSet, true); | |||
} | |||
@Override | |||
@@ -401,9 +356,8 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
"A new block is in process, cann't create another one until it finish by committing or canceling."); | |||
} | |||
LedgerBlock previousBlock = getLatestBlock(); | |||
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(previousBlock, | |||
getAdminInfo().getMetadata().getSetting(), keyPrefix, exPolicyStorage, | |||
versioningStorage); | |||
LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(previousBlock, getLatestSettings(), | |||
keyPrefix, exPolicyStorage, versioningStorage); | |||
NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this); | |||
this.nextBlockEditor = committingMonitor; | |||
return committingMonitor; | |||
@@ -426,64 +380,39 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
} | |||
static Bytes encodeLedgerIndexKey(HashDigest ledgerHash) { | |||
// return LEDGER_PREFIX + Base58Utils.encode(ledgerHash.toBytes()); | |||
// return new Bytes(ledgerHash.toBytes()).concatTo(LEDGER_PREFIX); | |||
return LEDGER_PREFIX.concat(ledgerHash); | |||
} | |||
static Bytes encodeBlockStorageKey(HashDigest blockHash) { | |||
// String key = ByteArray.toBase58(blockHash.toBytes()); | |||
// return BLOCK_PREFIX + key; | |||
return BLOCK_PREFIX.concat(blockHash); | |||
} | |||
static LedgerDataSetImpl newDataSet(LedgerInitSetting initSetting, String keyPrefix, | |||
static LedgerDataset newDataSet(LedgerInitSetting initSetting, String keyPrefix, | |||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||
LedgerAdminAccount adminAccount = new LedgerAdminAccount(initSetting, keyPrefix, ledgerExStorage, | |||
LedgerAdminDataset adminAccount = new LedgerAdminDataset(initSetting, keyPrefix, ledgerExStorage, | |||
ledgerVerStorage); | |||
String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | |||
String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | |||
String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | |||
// String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | |||
// UserAccountSet userAccountSet = new | |||
// UserAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerVerStorage), | |||
// DEFAULT_ACCESS_POLICY); | |||
UserAccountSet userAccountSet = new UserAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
UserAccountSet userAccountSet = new UserAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||
usersetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | |||
// DataAccountSet dataAccountSet = new | |||
// DataAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerVerStorage), | |||
// DEFAULT_ACCESS_POLICY); | |||
DataAccountSet dataAccountSet = new DataAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
DataAccountSet dataAccountSet = new DataAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||
datasetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | |||
// ContractAccountSet contractAccountSet = new | |||
// ContractAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerVerStorage), | |||
// DEFAULT_ACCESS_POLICY); | |||
ContractAccountSet contractAccountSet = new ContractAccountSet(adminAccount.getSetting().getCryptoSetting(), | |||
ContractAccountSet contractAccountSet = new ContractAccountSet(adminAccount.getSettings().getCryptoSetting(), | |||
contractsetKeyPrefix, ledgerExStorage, ledgerVerStorage, DEFAULT_ACCESS_POLICY); | |||
LedgerDataSetImpl newDataSet = new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, | |||
LedgerDataset newDataSet = new LedgerDataset(adminAccount, userAccountSet, dataAccountSet, | |||
contractAccountSet, false); | |||
return newDataSet; | |||
} | |||
static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, | |||
static TransactionSet newTransactionSet(LedgerSettings ledgerSetting, String keyPrefix, | |||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||
// TransactionSet transactionSet = new | |||
// TransactionSet(ledgerSetting.getCryptoSetting(), | |||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerVerStorage)); | |||
String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | |||
@@ -492,13 +421,11 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
return transactionSet; | |||
} | |||
static LedgerDataSetImpl loadDataSet(LedgerDataSnapshot dataSnapshot, String keyPrefix, | |||
static LedgerDataset loadDataSet(LedgerDataSnapshot dataSnapshot, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | |||
LedgerAdminAccount adminAccount = new LedgerAdminAccount(dataSnapshot.getAdminAccountHash(), keyPrefix, | |||
LedgerAdminDataset adminAccount = new LedgerAdminDataset(dataSnapshot.getAdminAccountHash(), keyPrefix, | |||
ledgerExStorage, ledgerVerStorage, readonly); | |||
CryptoSetting cryptoSetting = adminAccount.getPreviousSetting().getCryptoSetting(); | |||
UserAccountSet userAccountSet = loadUserAccountSet(dataSnapshot.getUserAccountSetHash(), cryptoSetting, | |||
keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | |||
@@ -508,7 +435,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
ContractAccountSet contractAccountSet = loadContractAccountSet(dataSnapshot.getContractAccountSetHash(), | |||
cryptoSetting, keyPrefix, ledgerExStorage, ledgerVerStorage, readonly); | |||
LedgerDataSetImpl dataset = new LedgerDataSetImpl(adminAccount, userAccountSet, dataAccountSet, | |||
LedgerDataset dataset = new LedgerDataset(adminAccount, userAccountSet, dataAccountSet, | |||
contractAccountSet, readonly); | |||
return dataset; | |||
@@ -517,10 +444,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
static UserAccountSet loadUserAccountSet(HashDigest userAccountSetHash, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | |||
boolean readonly) { | |||
// return new UserAccountSet(userAccountSetHash, cryptoSetting, | |||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(USER_SET_PREFIX, ledgerVerStorage), readonly, | |||
// DEFAULT_ACCESS_POLICY); | |||
String usersetKeyPrefix = keyPrefix + USER_SET_PREFIX; | |||
return new UserAccountSet(userAccountSetHash, cryptoSetting, usersetKeyPrefix, ledgerExStorage, | |||
@@ -530,10 +453,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
static DataAccountSet loadDataAccountSet(HashDigest dataAccountSetHash, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | |||
boolean readonly) { | |||
// return new DataAccountSet(dataAccountSetHash, cryptoSetting, | |||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerExStorage, | |||
// PrefixAppender.prefix(DATA_SET_PREFIX, ledgerVerStorage), readonly, | |||
// DEFAULT_ACCESS_POLICY); | |||
String datasetKeyPrefix = keyPrefix + DATA_SET_PREFIX; | |||
return new DataAccountSet(dataAccountSetHash, cryptoSetting, datasetKeyPrefix, ledgerExStorage, | |||
@@ -543,10 +462,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
static ContractAccountSet loadContractAccountSet(HashDigest contractAccountSetHash, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, | |||
boolean readonly) { | |||
// return new ContractAccountSet(contractAccountSetHash, cryptoSetting, | |||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerExStorage, | |||
// PrefixAppender.prefix(CONTRACT_SET_PREFIX, ledgerVerStorage), readonly, | |||
// DEFAULT_ACCESS_POLICY); | |||
String contractsetKeyPrefix = keyPrefix + CONTRACT_SET_PREFIX; | |||
return new ContractAccountSet(contractAccountSetHash, cryptoSetting, contractsetKeyPrefix, ledgerExStorage, | |||
@@ -555,9 +470,6 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
static TransactionSet loadTransactionSet(HashDigest txsetHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage, boolean readonly) { | |||
// return new TransactionSet(txsetHash, cryptoSetting, | |||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), | |||
// PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerVerStorage), readonly); | |||
String txsetKeyPrefix = keyPrefix + TRANSACTION_SET_PREFIX; | |||
return new TransactionSet(txsetHash, cryptoSetting, txsetKeyPrefix, ledgerExStorage, ledgerVerStorage, | |||
@@ -586,6 +498,16 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
return editor.getBlockHeight(); | |||
} | |||
@Override | |||
public LedgerDataset getLedgerDataset() { | |||
return editor.getLedgerDataset(); | |||
} | |||
@Override | |||
public TransactionSet getTransactionSet() { | |||
return editor.getTransactionSet(); | |||
} | |||
@Override | |||
public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | |||
return editor.newTransaction(txRequest); | |||
@@ -601,7 +523,8 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
try { | |||
editor.commit(); | |||
LedgerBlock latestBlock = editor.getCurrentBlock(); | |||
ledgerRepo.latestState = new LedgerState(latestBlock); | |||
ledgerRepo.latestState = new LedgerState(latestBlock, editor.getLedgerDataset(), | |||
editor.getTransactionSet()); | |||
} finally { | |||
ledgerRepo.nextBlockEditor = null; | |||
} | |||
@@ -628,20 +551,39 @@ public class LedgerRepositoryImpl implements LedgerRepository { | |||
private final LedgerBlock block; | |||
private volatile LedgerAdminAccount adminAccount; | |||
private final TransactionSet transactionSet; | |||
private volatile UserAccountSet userAccountSet; | |||
private final LedgerDataset ledgerDataset; | |||
private volatile DataAccountSet dataAccountSet; | |||
public LedgerState(LedgerBlock block, LedgerDataset ledgerDataset, TransactionSet transactionSet) { | |||
this.block = block; | |||
this.ledgerDataset = ledgerDataset; | |||
this.transactionSet = transactionSet; | |||
private volatile ContractAccountSet contractAccountSet; | |||
} | |||
private volatile TransactionSet transactionSet; | |||
public LedgerAdminDataset getAdminDataset() { | |||
return ledgerDataset.getAdminDataset(); | |||
} | |||
private volatile LedgerDataSet ledgerDataSet; | |||
public LedgerDataset getLedgerDataset() { | |||
return ledgerDataset; | |||
} | |||
public LedgerState(LedgerBlock block) { | |||
this.block = block; | |||
public ContractAccountQuery getContractAccountSet() { | |||
return ledgerDataset.getContractAccountset(); | |||
} | |||
public DataAccountQuery getDataAccountSet() { | |||
return ledgerDataset.getDataAccountSet(); | |||
} | |||
public UserAccountQuery getUserAccountSet() { | |||
return ledgerDataset.getUserAccountSet(); | |||
} | |||
public TransactionSet getTransactionSet() { | |||
return transactionSet; | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface LedgerSecurityManager { | |||
String DEFAULT_ROLE = "DEFAULT"; | |||
/** | |||
* 创建一项与指定的终端用户和节点参与方相关的安全策略; | |||
* | |||
* @param endpoints 终端用户的地址列表; | |||
* @param nodes 节点参与方的地址列表; | |||
* @return 一项安全策略; | |||
*/ | |||
SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes); | |||
} |
@@ -0,0 +1,396 @@ | |||
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.ParticipantDataQuery; | |||
import com.jd.blockchain.ledger.ParticipantDoesNotExistException; | |||
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.UserDoesNotExistException; | |||
import com.jd.blockchain.ledger.UserRoles; | |||
import com.jd.blockchain.ledger.UserRolesSettings; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 账本安全管理器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class LedgerSecurityManagerImpl implements LedgerSecurityManager { | |||
private RolePrivilegeSettings rolePrivilegeSettings; | |||
private UserRolesSettings userRolesSettings; | |||
// 用户的权限配置 | |||
private Map<Bytes, UserRolesPrivileges> userPrivilegesCache = new ConcurrentHashMap<>(); | |||
private Map<Bytes, UserRoles> userRolesCache = new ConcurrentHashMap<>(); | |||
private Map<String, RolePrivileges> rolesPrivilegeCache = new ConcurrentHashMap<>(); | |||
private ParticipantDataQuery participantsQuery; | |||
private UserAccountQuery userAccountsQuery; | |||
public LedgerSecurityManagerImpl(RolePrivilegeSettings rolePrivilegeSettings, UserRolesSettings userRolesSettings, | |||
ParticipantDataQuery participantsQuery, UserAccountQuery userAccountsQuery) { | |||
this.rolePrivilegeSettings = rolePrivilegeSettings; | |||
this.userRolesSettings = userRolesSettings; | |||
this.participantsQuery = participantsQuery; | |||
this.userAccountsQuery = userAccountsQuery; | |||
} | |||
@Override | |||
public SecurityPolicy createSecurityPolicy(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, participantsQuery, userAccountsQuery); | |||
} | |||
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<>(); | |||
private ParticipantDataQuery participantsQuery; | |||
private UserAccountQuery userAccountsQuery; | |||
public UserRolesSecurityPolicy(Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap, | |||
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap, ParticipantDataQuery participantsQuery, | |||
UserAccountQuery userAccountsQuery) { | |||
this.endpointPrivilegeMap = endpointPrivilegeMap; | |||
this.nodePrivilegeMap = nodePrivilegeMap; | |||
this.participantsQuery = participantsQuery; | |||
this.userAccountsQuery = userAccountsQuery; | |||
} | |||
@Override | |||
public boolean isEndpointEnable(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 isEndpointEnable(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 isNodeEnable(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 isNodeEnable(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 checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isEndpointEnable(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 checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isEndpointEnable(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 checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isNodeEnable(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 checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException { | |||
if (!isNodeEnable(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(); | |||
} | |||
@Override | |||
public boolean isEndpointValid(MultiIDsPolicy midPolicy) { | |||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (Bytes address : getEndpoints()) { | |||
if (userAccountsQuery.contains(address)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (Bytes address : getEndpoints()) { | |||
if (!userAccountsQuery.contains(address)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public boolean isNodeValid(MultiIDsPolicy midPolicy) { | |||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (Bytes address : getNodes()) { | |||
if (participantsQuery.contains(address)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (Bytes address : getNodes()) { | |||
if (!participantsQuery.contains(address)) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (Bytes address : getEndpoints()) { | |||
if (userAccountsQuery.contains(address)) { | |||
return; | |||
} | |||
} | |||
throw new UserDoesNotExistException("All endpoint signers were not registered!"); | |||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (Bytes address : getEndpoints()) { | |||
if (!userAccountsQuery.contains(address)) { | |||
throw new UserDoesNotExistException("The endpoint signer[" + address + "] was not registered!"); | |||
} | |||
} | |||
return; | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
@Override | |||
public void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException { | |||
if (MultiIDsPolicy.AT_LEAST_ONE == midPolicy) { | |||
// 至少一个; | |||
for (Bytes address : getNodes()) { | |||
if (participantsQuery.contains(address)) { | |||
return; | |||
} | |||
} | |||
throw new ParticipantDoesNotExistException("All node signers were not registered as participant!"); | |||
} else if (MultiIDsPolicy.ALL == midPolicy) { | |||
// 全部; | |||
for (Bytes address : getNodes()) { | |||
if (!participantsQuery.contains(address)) { | |||
throw new ParticipantDoesNotExistException( | |||
"The node signer[" + address + "] was not registered as participant!"); | |||
} | |||
} | |||
} else { | |||
throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); | |||
} | |||
} | |||
} | |||
} |
@@ -13,11 +13,18 @@ import java.util.List; | |||
public interface LedgerTransactionContext { | |||
/** | |||
* 账本数据; | |||
* 账本数据集合; | |||
* | |||
* @return | |||
*/ | |||
LedgerDataSet getDataSet(); | |||
LedgerDataset getDataset(); | |||
/** | |||
* 事务集合; | |||
* | |||
* @return | |||
*/ | |||
TransactionSet getTransactionSet(); | |||
/** | |||
* 交易请求; | |||
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.List; | |||
@@ -8,29 +8,19 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockBody; | |||
import com.jd.blockchain.ledger.BlockRollbackException; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.IllegalTransactionException; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerDataSnapshot; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerSetting; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRollbackException; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.ledger.core.SettingContext; | |||
import com.jd.blockchain.ledger.core.TransactionSet; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | |||
import com.jd.blockchain.transaction.SignatureUtils; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.transaction.TxRequestBuilder; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
@@ -70,10 +60,8 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
private BufferedKVStorage baseStorage; | |||
/** | |||
* 上一个交易的上下文; | |||
* 上一个交易产生的账本快照; | |||
*/ | |||
// private LedgerTransactionContextImpl previousTxCtx; | |||
private TxSnapshot previousTxSnapshot; | |||
/** | |||
@@ -81,6 +69,16 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
*/ | |||
private volatile LedgerTransactionContextImpl currentTxCtx; | |||
/** | |||
* 最后提交的账本数据集; | |||
*/ | |||
private volatile LedgerDataset latestLedgerDataset; | |||
/** | |||
* 最后提交的交易集合; | |||
*/ | |||
private volatile TransactionSet latestTransactionSet; | |||
/** | |||
* @param ledgerHash | |||
* @param cryptoSetting | |||
@@ -115,7 +113,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
* @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; | |||
* @return | |||
*/ | |||
public static LedgerTransactionalEditor createEditor(LedgerBlock previousBlock, LedgerSetting ledgerSetting, | |||
public static LedgerTransactionalEditor createEditor(LedgerBlock previousBlock, LedgerSettings ledgerSetting, | |||
String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { | |||
// new block; | |||
HashDigest ledgerHash = previousBlock.getLedgerHash(); | |||
@@ -160,6 +158,10 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
private void commitTxSnapshot(TxSnapshot snapshot) { | |||
previousTxSnapshot = snapshot; | |||
latestLedgerDataset = currentTxCtx.getDataset(); | |||
latestLedgerDataset.setReadonly(); | |||
latestTransactionSet = currentTxCtx.getTransactionSet(); | |||
latestTransactionSet.setReadonly(); | |||
currentTxCtx = null; | |||
} | |||
@@ -181,13 +183,23 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
return ledgerHash; | |||
} | |||
@Override | |||
public LedgerDataset getLedgerDataset() { | |||
return latestLedgerDataset; | |||
} | |||
@Override | |||
public TransactionSet getTransactionSet() { | |||
return latestTransactionSet; | |||
} | |||
/** | |||
* 检查当前账本是否是指定交易请求的账本; | |||
* | |||
* @param txRequest | |||
* @return | |||
*/ | |||
private boolean isRequestedLedger(TransactionRequest txRequest) { | |||
private boolean isRequestMatched(TransactionRequest txRequest) { | |||
HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash(); | |||
if (ledgerHash == reqLedgerHash) { | |||
return true; | |||
@@ -198,49 +210,19 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
return ledgerHash.equals(reqLedgerHash); | |||
} | |||
private boolean verifyTxContent(TransactionRequest request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
return false; | |||
} | |||
DigitalSignature[] endpointSignatures = request.getEndpointSignatures(); | |||
if (endpointSignatures != null) { | |||
for (DigitalSignature signature : endpointSignatures) { | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), | |||
signature.getPubKey())) { | |||
return false; | |||
} | |||
} | |||
} | |||
DigitalSignature[] nodeSignatures = request.getNodeSignatures(); | |||
if (nodeSignatures != null) { | |||
for (DigitalSignature signature : nodeSignatures) { | |||
if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), | |||
signature.getPubKey())) { | |||
return false; | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* 注:此方法不验证交易完整性和签名有效性,仅仅设计为进行交易记录的管理;调用者应在此方法之外进行数据完整性和签名有效性的检查; | |||
*/ | |||
@Override | |||
public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { | |||
if (SettingContext.txSettings().verifyLedger() && !isRequestedLedger(txRequest)) { | |||
// if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { | |||
if (!isRequestMatched(txRequest)) { | |||
throw new IllegalTransactionException( | |||
"Transaction request is dispatched to a wrong ledger! --[TxHash=" | |||
+ txRequest.getTransactionContent().getHash() + "]!", | |||
TransactionState.IGNORED_BY_WRONG_LEDGER); | |||
} | |||
// TODO: 把验签和创建交易并行化; | |||
if (SettingContext.txSettings().verifySignature() && !verifyTxContent(txRequest)) { | |||
// 抛弃哈希和签名校验失败的交易请求; | |||
throw new IllegalTransactionException( | |||
"Wrong transaction signature! --[TxHash=" + txRequest.getTransactionContent().getHash() + "]!", | |||
TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
} | |||
if (currentTxCtx != null) { | |||
throw new IllegalStateException( | |||
"Unable to open another new transaction before the current transaction is completed! --[TxHash=" | |||
@@ -253,7 +235,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
// init storage of new transaction; | |||
BufferedKVStorage txBufferedStorage = new BufferedKVStorage(baseStorage, baseStorage, false); | |||
LedgerDataSetImpl txDataset = null; | |||
LedgerDataset txDataset = null; | |||
TransactionSet txset = null; | |||
if (previousTxSnapshot == null) { | |||
// load the starting point of the new transaction; | |||
@@ -262,18 +244,18 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
GenesisSnapshot snpht = (GenesisSnapshot) startingPoint; | |||
txDataset = LedgerRepositoryImpl.newDataSet(snpht.initSetting, ledgerKeyPrefix, txBufferedStorage, | |||
txBufferedStorage); | |||
txset = LedgerRepositoryImpl.newTransactionSet(txDataset.getAdminAccount().getSetting(), | |||
txset = LedgerRepositoryImpl.newTransactionSet(txDataset.getAdminDataset().getSettings(), | |||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage); | |||
} else if (startingPoint instanceof TxSnapshot) { | |||
// 新的区块; | |||
// TxSnapshot; reload dataset and txset; | |||
TxSnapshot snpht = (TxSnapshot) startingPoint; | |||
// load dataset; | |||
txDataset = LedgerRepositoryImpl.loadDataSet(snpht.dataSnapshot, ledgerKeyPrefix, txBufferedStorage, | |||
txBufferedStorage, false); | |||
txDataset = LedgerRepositoryImpl.loadDataSet(snpht.dataSnapshot, cryptoSetting, ledgerKeyPrefix, | |||
txBufferedStorage, txBufferedStorage, false); | |||
// load txset; | |||
txset = LedgerRepositoryImpl.loadTransactionSet(snpht.txsetHash, this.cryptoSetting, ledgerKeyPrefix, | |||
txset = LedgerRepositoryImpl.loadTransactionSet(snpht.txsetHash, cryptoSetting, ledgerKeyPrefix, | |||
txBufferedStorage, txBufferedStorage, false); | |||
} else { | |||
// Unreachable; | |||
@@ -283,11 +265,11 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
} else { | |||
// Reuse previous object to optimize performance; | |||
// load dataset; | |||
txDataset = LedgerRepositoryImpl.loadDataSet(previousTxSnapshot.dataSnapshot, ledgerKeyPrefix, | |||
txBufferedStorage, txBufferedStorage, false); | |||
txDataset = LedgerRepositoryImpl.loadDataSet(previousTxSnapshot.dataSnapshot, cryptoSetting, | |||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage, false); | |||
// load txset; | |||
txset = LedgerRepositoryImpl.loadTransactionSet(previousTxSnapshot.txsetHash, this.cryptoSetting, | |||
txset = LedgerRepositoryImpl.loadTransactionSet(previousTxSnapshot.txsetHash, cryptoSetting, | |||
ledgerKeyPrefix, txBufferedStorage, txBufferedStorage, false); | |||
} | |||
@@ -476,28 +458,6 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
} | |||
// /** | |||
// * 账本的数据上下文; | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
// private static class LedgerDataContext { | |||
// | |||
// protected LedgerDataSetImpl dataset; | |||
// | |||
// protected TransactionSet txset; | |||
// | |||
// protected BufferedKVStorage storage; | |||
// | |||
// public LedgerDataContext(LedgerDataSetImpl dataset, TransactionSet txset, BufferedKVStorage storage) { | |||
// this.dataset = dataset; | |||
// this.txset = txset; | |||
// this.storage = storage; | |||
// } | |||
// | |||
// } | |||
/** | |||
* 交易的上下文; | |||
* | |||
@@ -510,7 +470,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
private TransactionRequest txRequest; | |||
private LedgerDataSetImpl dataset; | |||
private LedgerDataset dataset; | |||
private TransactionSet txset; | |||
@@ -524,7 +484,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
private HashDigest txRootHash; | |||
private LedgerTransactionContextImpl(TransactionRequest txRequest, LedgerDataSetImpl dataset, | |||
private LedgerTransactionContextImpl(TransactionRequest txRequest, LedgerDataset dataset, | |||
TransactionSet txset, BufferedKVStorage storage, LedgerTransactionalEditor editor) { | |||
this.txRequest = txRequest; | |||
this.dataset = dataset; | |||
@@ -534,10 +494,15 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
} | |||
@Override | |||
public LedgerDataSet getDataSet() { | |||
public LedgerDataset getDataset() { | |||
return dataset; | |||
} | |||
@Override | |||
public TransactionSet getTransactionSet() { | |||
return txset; | |||
} | |||
@Override | |||
public TransactionRequest getTransactionRequest() { | |||
return txRequest; | |||
@@ -620,8 +585,8 @@ public class LedgerTransactionalEditor implements LedgerEditor { | |||
private TransactionStagedSnapshot takeDataSnapshot() { | |||
TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); | |||
txDataSnapshot.setAdminAccountHash(dataset.getAdminAccount().getHash()); | |||
txDataSnapshot.setContractAccountSetHash(dataset.getContractAccountSet().getRootHash()); | |||
txDataSnapshot.setAdminAccountHash(dataset.getAdminDataset().getHash()); | |||
txDataSnapshot.setContractAccountSetHash(dataset.getContractAccountset().getRootHash()); | |||
txDataSnapshot.setDataAccountSetHash(dataset.getDataAccountSet().getRootHash()); | |||
txDataSnapshot.setUserAccountSetHash(dataset.getUserAccountSet().getRootHash()); | |||
return txDataSnapshot; |
@@ -1,5 +1,6 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
public interface MerkleDataEntry { | |||
@@ -3,11 +3,14 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleDataNode; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | |||
import com.jd.blockchain.storage.service.utils.VersioningKVData; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
@@ -62,12 +65,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
/** | |||
* 创建一个新的 MerkleDataSet; | |||
* | |||
* @param setting | |||
* 密码设置; | |||
* @param exPolicyStorage | |||
* 默克尔树的存储; | |||
* @param versioningStorage | |||
* 数据的存储; | |||
* @param setting 密码设置; | |||
* @param exPolicyStorage 默克尔树的存储; | |||
* @param versioningStorage 数据的存储; | |||
*/ | |||
public MerkleDataSet(CryptoSetting setting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
@@ -126,6 +126,10 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return readonly; | |||
} | |||
void setReadonly() { | |||
this.readonly = true; | |||
} | |||
public long getDataCount() { | |||
return merkleTree.getDataCount(); | |||
} | |||
@@ -150,8 +154,27 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return values; | |||
} | |||
public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) { | |||
if (count > LedgerConsts.MAX_LIST_COUNT) { | |||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
} | |||
if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | |||
throw new IllegalArgumentException("Index out of bound!"); | |||
} | |||
VersioningKVEntry[] values = new VersioningKVEntry[count]; | |||
byte[] bytesValue; | |||
for (int i = 0; i < count; i++) { | |||
MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | |||
Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); | |||
values[i] = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), bytesValue); | |||
} | |||
return values; | |||
} | |||
/** | |||
* get the data at the specific index; | |||
* | |||
* @param fromIndex | |||
* @return | |||
*/ | |||
@@ -163,6 +186,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
/** | |||
* get the key at the specific index; | |||
* | |||
* @param fromIndex | |||
* @return | |||
*/ | |||
@@ -171,7 +195,6 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return dataNode.getKey().toUTF8String(); | |||
} | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
@@ -183,12 +206,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* If updating is performed, the version of the key increase by 1. <br> | |||
* If creating is performed, the version of the key initialize by 0. <br> | |||
* | |||
* @param key | |||
* The key of data; | |||
* @param value | |||
* The value of data; | |||
* @param version | |||
* The expected latest version of the key. | |||
* @param key The key of data; | |||
* @param value The value of data; | |||
* @param version The expected latest version of the key. | |||
* @return The new version of the key. <br> | |||
* If the key is new created success, then return 0; <br> | |||
* If the key is updated success, then return the new version;<br> | |||
@@ -210,12 +230,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* If updating is performed, the version of the key increase by 1. <br> | |||
* If creating is performed, the version of the key initialize by 0. <br> | |||
* | |||
* @param key | |||
* The key of data; | |||
* @param value | |||
* The value of data; | |||
* @param version | |||
* The expected latest version of the key. | |||
* @param key The key of data; | |||
* @param value The value of data; | |||
* @param version The expected latest version of the key. | |||
* @return The new version of the key. <br> | |||
* If the key is new created success, then return 0; <br> | |||
* If the key is updated success, then return the new version;<br> | |||
@@ -404,12 +421,22 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return getDataEntry(Bytes.fromString(key)); | |||
} | |||
/** | |||
* | |||
* @param key | |||
* @return Null if the key doesn't exist! | |||
*/ | |||
public VersioningKVEntry getDataEntry(Bytes key) { | |||
long latestVersion = getMerkleVersion(key); | |||
if (latestVersion < 0) { | |||
return null; | |||
} | |||
return valueStorage.getEntry(key, latestVersion); | |||
Bytes dataKey = encodeDataKey(key); | |||
byte[] value = valueStorage.get(dataKey, latestVersion); | |||
if (value == null) { | |||
return null; | |||
} | |||
return new VersioningKVData(key, latestVersion, value); | |||
} | |||
public VersioningKVEntry getDataEntry(Bytes key, long version) { | |||
@@ -420,7 +447,12 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return null; | |||
} | |||
version = version < 0 ? latestVersion : version; | |||
return valueStorage.getEntry(key, version); | |||
Bytes dataKey = encodeDataKey(key); | |||
byte[] value = valueStorage.get(dataKey, version); | |||
if (value == null) { | |||
return null; | |||
} | |||
return new VersioningKVData(key, version, value); | |||
} | |||
public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | |||
@@ -1,6 +1,7 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface MerkleProvable { | |||
@@ -20,6 +20,9 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleDataNode; | |||
import com.jd.blockchain.ledger.MerkleNode; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -0,0 +1,21 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* 多重身份的校验策略; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum MultiIDsPolicy { | |||
/** | |||
* 至少有一个都能通过; | |||
*/ | |||
AT_LEAST_ONE, | |||
/** | |||
* 每一个都能通过; | |||
*/ | |||
ALL | |||
} |
@@ -1,8 +1,7 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.core.AccountAccessPolicy; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** |
@@ -2,8 +2,6 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
public interface OperationHandle { | |||
@@ -13,42 +11,22 @@ public interface OperationHandle { | |||
* @param operationType | |||
* @return | |||
*/ | |||
boolean support(Class<?> operationType); | |||
Class<?> getOperationType(); | |||
/** | |||
* 同步解析和执行操作; | |||
* | |||
* | |||
* @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, | |||
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||
BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataQuery 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); | |||
} |
@@ -0,0 +1,15 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.Operation; | |||
/** | |||
* 在交易处理过程中,提供对多种交易操作处理器互相调用的机制; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface OperationHandleContext { | |||
void handle(Operation operation); | |||
} |
@@ -0,0 +1,9 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.Operation; | |||
public interface OperationHandleRegisteration { | |||
OperationHandle getHandle(Class<? extends Operation> operationType); | |||
} |
@@ -1,21 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
/** | |||
* @author hhq | |||
* @version 1.0 | |||
* @created 14-6��-2018 12:13:33 | |||
*/ | |||
public class P2PRealm { | |||
public Peer m_Peer; | |||
public P2PRealm(){ | |||
} | |||
public void finalize() throws Throwable { | |||
} | |||
} |
@@ -2,6 +2,7 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.ledger.ParticipantNodeState; | |||
/** | |||
@@ -13,7 +14,7 @@ import com.jd.blockchain.ledger.ParticipantNodeState; | |||
public class ParticipantCertData implements ParticipantNode { | |||
private int id; | |||
private String address; | |||
private Bytes address; | |||
private String name; | |||
private PubKey pubKey; | |||
private ParticipantNodeState participantNodeState; | |||
@@ -29,14 +30,14 @@ public class ParticipantCertData implements ParticipantNode { | |||
this.participantNodeState = participantNode.getParticipantNodeState(); | |||
} | |||
public ParticipantCertData(String address, String name, PubKey pubKey) { | |||
public ParticipantCertData(Bytes address, String name, PubKey pubKey) { | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
} | |||
@Override | |||
public String getAddress() { | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@@ -4,14 +4,16 @@ import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.ParticipantDataQuery; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
public class ParticipantDataset implements Transactional, MerkleProvable, ParticipantDataQuery { | |||
static { | |||
DataContractRegistry.register(ParticipantNode.class); | |||
@@ -19,12 +21,12 @@ public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
private MerkleDataSet dataset; | |||
public ParticipantDataSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||
public ParticipantDataset(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage verStorage) { | |||
dataset = new MerkleDataSet(cryptoSetting, prefix, exPolicyStorage, verStorage); | |||
} | |||
public ParticipantDataSet(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
public ParticipantDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
} | |||
@@ -54,6 +56,7 @@ public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
dataset.cancel(); | |||
} | |||
@Override | |||
public long getParticipantCount() { | |||
return dataset.getDataCount(); | |||
} | |||
@@ -92,9 +95,15 @@ public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
} | |||
} | |||
private Bytes encodeKey(String address) { | |||
// return id + ""; | |||
return Bytes.fromString(address); | |||
private Bytes encodeKey(Bytes address) { | |||
return address; | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
Bytes key = encodeKey(address); | |||
long latestVersion = dataset.getVersion(key); | |||
return latestVersion > -1; | |||
} | |||
/** | |||
@@ -106,7 +115,8 @@ public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
* @param address | |||
* @return | |||
*/ | |||
public ParticipantNode getParticipant(String address) { | |||
@Override | |||
public ParticipantNode getParticipant(Bytes address) { | |||
Bytes key = encodeKey(address); | |||
byte[] bytes = dataset.getValue(key); | |||
if (bytes == null) { | |||
@@ -114,11 +124,12 @@ public class ParticipantDataSet implements Transactional, MerkleProvable { | |||
} | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
@Override | |||
public ParticipantNode[] getParticipants() { | |||
byte[][] bytes = dataset.getLatestValues(0, (int)dataset.getDataCount()); | |||
byte[][] bytes = dataset.getLatestValues(0, (int) dataset.getDataCount()); | |||
ParticipantNode[] pns = new ParticipantNode[bytes.length]; | |||
for (int i = 0; i < pns.length; i++) { | |||
pns[i] = BinaryProtocol.decode(bytes[i]); | |||
} |
@@ -1,7 +1,5 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.SortedSet; | |||
public interface PermissionService { | |||
boolean checkLedgerPermission(); | |||
@@ -1,21 +0,0 @@ | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//import com.jd.blockchain.crypto.hash.HashDigest; | |||
//import com.jd.blockchain.ledger.data.DigitalSignatureBlob; | |||
// | |||
//import my.utils.io.ExistentialKVStorage; | |||
//import my.utils.io.VersioningKVStorage; | |||
// | |||
//public class PrivilegeDataSet extends GenericMerkleDataSet<Authorization, AuthorizationVO> { | |||
// | |||
// public PrivilegeDataSet(CryptoSetting setting, ExistentialKVStorage merkleTreeStorage, VersioningKVStorage dataStorage) { | |||
// this(null, setting, merkleTreeStorage, dataStorage, false); | |||
// } | |||
// | |||
// public PrivilegeDataSet(HashDigest rootHash, CryptoSetting setting, ExistentialKVStorage merkleTreeStorage, | |||
// VersioningKVStorage dataStorage, boolean readonly) { | |||
// super(rootHash, setting, merkleTreeStorage, dataStorage, readonly, Authorization.class, AuthorizationVO.class, | |||
// DigitalSignatureBlob.class); | |||
// } | |||
// | |||
//} |
@@ -0,0 +1,293 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerPrivilege; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.PrivilegeSet; | |||
import com.jd.blockchain.ledger.Privileges; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionPrivilege; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class RolePrivilegeDataset implements Transactional, MerkleProvable, RolePrivilegeSettings { | |||
private MerkleDataSet dataset; | |||
public RolePrivilegeDataset(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage verStorage) { | |||
dataset = new MerkleDataSet(cryptoSetting, prefix, exPolicyStorage, verStorage); | |||
} | |||
public RolePrivilegeDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return dataset.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return dataset.getProof(key); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return dataset.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
dataset.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
dataset.cancel(); | |||
} | |||
@Override | |||
public long getRoleCount() { | |||
return dataset.getDataCount(); | |||
} | |||
@Override | |||
public long addRolePrivilege(String roleName, Privileges privileges) { | |||
return addRolePrivilege(roleName, privileges.getLedgerPrivilege(), privileges.getTransactionPrivilege()); | |||
} | |||
@Override | |||
public long addRolePrivilege(String roleName, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | |||
RolePrivileges roleAuth = new RolePrivileges(roleName, -1, ledgerPrivilege, txPrivilege); | |||
long nv = setRolePrivilege(roleAuth); | |||
if (nv < 0) { | |||
throw new LedgerException("Role[" + roleName + "] already exist!"); | |||
} | |||
return nv; | |||
} | |||
@Override | |||
public long addRolePrivilege(String roleName, LedgerPermission[] ledgerPermissions, | |||
TransactionPermission[] txPermissions) { | |||
LedgerPrivilege ledgerPrivilege = new LedgerPrivilege(); | |||
for (LedgerPermission lp : ledgerPermissions) { | |||
ledgerPrivilege.enable(lp); | |||
} | |||
TransactionPrivilege txPrivilege = new TransactionPrivilege(); | |||
for (TransactionPermission tp : txPermissions) { | |||
txPrivilege.enable(tp); | |||
} | |||
return addRolePrivilege(roleName, ledgerPrivilege, txPrivilege); | |||
} | |||
/** | |||
* 设置角色权限; <br> | |||
* 如果版本校验不匹配,则返回 -1; | |||
* | |||
* @param roleAuth | |||
* @return | |||
*/ | |||
private long setRolePrivilege(RolePrivileges roleAuth) { | |||
if (roleAuth.getRoleName().length() > MAX_ROLE_NAME_LENGTH) { | |||
throw new LedgerException("Too long role name!"); | |||
} | |||
Bytes key = encodeKey(roleAuth.getRoleName()); | |||
byte[] privilegeBytes = BinaryProtocol.encode(roleAuth, PrivilegeSet.class); | |||
return dataset.setValue(key, privilegeBytes, roleAuth.getVersion()); | |||
} | |||
/** | |||
* 更新角色权限; <br> | |||
* 如果指定的角色不存在,或者版本不匹配,则引发 {@link LedgerException} 异常; | |||
* | |||
* @param participant | |||
*/ | |||
@Override | |||
public void updateRolePrivilege(RolePrivileges roleAuth) { | |||
long nv = setRolePrivilege(roleAuth); | |||
if (nv < 0) { | |||
throw new LedgerException("Update to RoleAuthorization[" + roleAuth.getRoleName() | |||
+ "] failed due to wrong version[" + roleAuth.getVersion() + "] !"); | |||
} | |||
} | |||
/** | |||
* 授权角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName 角色; | |||
* @param permissions 权限列表; | |||
* @return | |||
*/ | |||
@Override | |||
public long enablePermissions(String roleName, LedgerPermission... permissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getLedgerPrivilege().enable(permissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
/** | |||
* 授权角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName 角色; | |||
* @param permissions 权限列表; | |||
* @return | |||
*/ | |||
@Override | |||
public long enablePermissions(String roleName, TransactionPermission... permissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getTransactionPrivilege().enable(permissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
/** | |||
* 禁止角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName 角色; | |||
* @param permissions 权限列表; | |||
* @return | |||
*/ | |||
@Override | |||
public long disablePermissions(String roleName, LedgerPermission... permissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getLedgerPrivilege().disable(permissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
/** | |||
* 禁止角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName 角色; | |||
* @param permissions 权限列表; | |||
* @return | |||
*/ | |||
@Override | |||
public long disablePermissions(String roleName, TransactionPermission... permissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getTransactionPrivilege().disable(permissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
/** | |||
* 授权角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName | |||
* @param ledgerPermissions | |||
* @param txPermissions | |||
* @return | |||
*/ | |||
@Override | |||
public long enablePermissions(String roleName, LedgerPermission[] ledgerPermissions, | |||
TransactionPermission[] txPermissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getLedgerPrivilege().enable(ledgerPermissions); | |||
roleAuth.getTransactionPrivilege().enable(txPermissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
/** | |||
* 禁用角色指定的权限; <br> | |||
* 如果角色不存在,则返回 -1; | |||
* | |||
* @param roleName | |||
* @param ledgerPermissions | |||
* @param txPermissions | |||
* @return | |||
*/ | |||
@Override | |||
public long disablePermissions(String roleName, LedgerPermission[] ledgerPermissions, | |||
TransactionPermission[] txPermissions) { | |||
RolePrivileges roleAuth = getRolePrivilege(roleName); | |||
if (roleAuth == null) { | |||
return -1; | |||
} | |||
roleAuth.getLedgerPrivilege().disable(ledgerPermissions); | |||
roleAuth.getTransactionPrivilege().disable(txPermissions); | |||
return setRolePrivilege(roleAuth); | |||
} | |||
private Bytes encodeKey(String address) { | |||
// return id + ""; | |||
return Bytes.fromString(address); | |||
} | |||
/** | |||
* 查询角色权限; | |||
* | |||
* <br> | |||
* 如果不存在,则返回 null; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public RolePrivileges getRolePrivilege(String roleName) { | |||
// 只返回最新版本; | |||
Bytes key = encodeKey(roleName); | |||
VersioningKVEntry kv = dataset.getDataEntry(key); | |||
if (kv == null) { | |||
return null; | |||
} | |||
PrivilegeSet privilege = BinaryProtocol.decode(kv.getValue()); | |||
return new RolePrivileges(roleName, kv.getVersion(), privilege); | |||
} | |||
@Override | |||
public RolePrivileges[] getRolePrivileges(int index, int count) { | |||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(index, count); | |||
RolePrivileges[] pns = new RolePrivileges[kvEntries.length]; | |||
PrivilegeSet privilege; | |||
for (int i = 0; i < pns.length; i++) { | |||
privilege = BinaryProtocol.decode(kvEntries[i].getValue()); | |||
pns[i] = new RolePrivileges(kvEntries[i].getKey().toUTF8String(), kvEntries[i].getVersion(), privilege); | |||
} | |||
return pns; | |||
} | |||
@Override | |||
public RolePrivileges[] getRolePrivileges() { | |||
return getRolePrivileges(0, (int) getRoleCount()); | |||
} | |||
@Override | |||
public boolean isReadonly() { | |||
return dataset.isReadonly(); | |||
} | |||
@Override | |||
public boolean contains(String roleName) { | |||
Bytes key = encodeKey(roleName); | |||
return dataset.getVersion(key) > -1; | |||
} | |||
} |
@@ -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,142 @@ | |||
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(); | |||
/** | |||
* 终端身份是否合法; | |||
* | |||
* @param midPolicy | |||
* @return | |||
*/ | |||
boolean isEndpointValid(MultiIDsPolicy midPolicy); | |||
/** | |||
* 节点身份是否合法; | |||
* | |||
* @param midPolicy | |||
* @return | |||
*/ | |||
boolean isNodeValid(MultiIDsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEndpointEnable(LedgerPermission permission, MultiIDsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isEndpointEnable(TransactionPermission permission, MultiIDsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isNodeEnable(LedgerPermission permission, MultiIDsPolicy midPolicy); | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @return 返回 true 表示获得授权; 返回 false 表示未获得授权; | |||
*/ | |||
boolean isNodeEnable(TransactionPermission permission, MultiIDsPolicy midPolicy); | |||
/** | |||
* 检查终端身份的合法性; | |||
* | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkEndpointValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查节点身份的合法性; | |||
* | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkNodeValidity(MultiIDsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission 要检查的权限; | |||
* @param midPolicy 针对多个签名用户的权限策略; | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkEndpointPermission(LedgerPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkEndpointPermission(TransactionPermission permission, MultiIDsPolicy midPolicy) | |||
throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkNodePermission(LedgerPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException; | |||
/** | |||
* 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;<br> | |||
* 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; | |||
* | |||
* @param permission | |||
* @param midPolicy | |||
* @throws LedgerSecurityException | |||
*/ | |||
void checkNodePermission(TransactionPermission permission, MultiIDsPolicy midPolicy) throws LedgerSecurityException; | |||
} |
@@ -1,51 +1,51 @@ | |||
package com.jd.blockchain.ledger.core; | |||
public class SettingContext { | |||
private static final TxSettingContext txSettings = new TxSettingContext(); | |||
private static final QueryingSettingContext queryingSettings = new QueryingSettingContext(); | |||
public static TxSettingContext txSettings() { | |||
return txSettings; | |||
} | |||
public static QueryingSettingContext queryingSettings() { | |||
return queryingSettings; | |||
} | |||
/** | |||
* 与交易处理相关的设置; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public static class TxSettingContext { | |||
public boolean verifyLedger() { | |||
return true; | |||
} | |||
public boolean verifySignature() { | |||
return true; | |||
} | |||
} | |||
/** | |||
* 与账本查询相关的设置; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public static class QueryingSettingContext { | |||
/** | |||
* 查询区块等具有 hash 标识符的对象时是否重新校验哈希; | |||
* @return | |||
*/ | |||
public boolean verifyHash() { | |||
return false; | |||
} | |||
} | |||
} | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//public class SettingContext { | |||
// | |||
// private static final TxSettingContext txSettings = new TxSettingContext(); | |||
// | |||
// private static final QueryingSettingContext queryingSettings = new QueryingSettingContext(); | |||
// | |||
// public static TxSettingContext txSettings() { | |||
// return txSettings; | |||
// } | |||
// | |||
// public static QueryingSettingContext queryingSettings() { | |||
// return queryingSettings; | |||
// } | |||
// | |||
// /** | |||
// * 与交易处理相关的设置; | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
// public static class TxSettingContext { | |||
// | |||
// public boolean verifyLedger() { | |||
// return true; | |||
// } | |||
// | |||
// public boolean verifySignature() { | |||
// return true; | |||
// } | |||
// | |||
// } | |||
// | |||
// /** | |||
// * 与账本查询相关的设置; | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
// public static class QueryingSettingContext { | |||
// | |||
// /** | |||
// * 查询区块等具有 hash 标识符的对象时是否重新校验哈希; | |||
// * @return | |||
// */ | |||
// public boolean verifyHash() { | |||
// return false; | |||
// } | |||
// | |||
// } | |||
// | |||
//} |
@@ -1,6 +1,7 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
@@ -15,35 +16,37 @@ import com.jd.blockchain.ledger.DataAccountDoesNotExistException; | |||
import com.jd.blockchain.ledger.IllegalTransactionException; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerSecurityException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.OperationResultData; | |||
import com.jd.blockchain.ledger.ParticipantDoesNotExistException; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionRollbackException; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.UserDoesNotExistException; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension.Credential; | |||
import com.jd.blockchain.service.TransactionBatchProcess; | |||
import com.jd.blockchain.service.TransactionBatchResult; | |||
import com.jd.blockchain.service.TransactionBatchResultHandle; | |||
import com.jd.blockchain.transaction.SignatureUtils; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.transaction.TxResponseMessage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); | |||
private LedgerSecurityManager securityManager; | |||
private LedgerService ledgerService; | |||
private LedgerEditor newBlockEditor; | |||
private LedgerDataSet previousBlockDataset; | |||
private LedgerDataQuery ledgerQueryer; | |||
private OperationHandleRegisteration opHandles; | |||
@@ -57,14 +60,15 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
private TransactionBatchResult batchResult; | |||
/** | |||
* @param newBlockEditor 新区块的数据编辑器; | |||
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param opHandles 操作处理对象注册表; | |||
* @param newBlockEditor 新区块的数据编辑器; | |||
* @param ledgerQueryer 账本查询器,只包含新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
* @param opHandles 操作处理对象注册表; | |||
*/ | |||
public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset, | |||
OperationHandleRegisteration opHandles, LedgerService ledgerService) { | |||
public TransactionBatchProcessor(LedgerSecurityManager securityManager, LedgerEditor newBlockEditor, | |||
LedgerDataQuery ledgerQueryer, OperationHandleRegisteration opHandles, LedgerService ledgerService) { | |||
this.securityManager = securityManager; | |||
this.newBlockEditor = newBlockEditor; | |||
this.previousBlockDataset = previousBlockDataset; | |||
this.ledgerQueryer = ledgerQueryer; | |||
this.opHandles = opHandles; | |||
this.ledgerService = ledgerService; | |||
} | |||
@@ -82,12 +86,26 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
try { | |||
LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
TransactionRequestExtension reqExt = new TransactionRequestExtensionImpl(request); | |||
// 初始化交易的用户安全策略; | |||
SecurityPolicy securityPolicy = securityManager.createSecurityPolicy(reqExt.getEndpointAddresses(), | |||
reqExt.getNodeAddresses()); | |||
SecurityContext.setContextUsersPolicy(securityPolicy); | |||
// 安全校验; | |||
checkSecurity(securityPolicy); | |||
// 验证交易请求; | |||
checkRequest(reqExt); | |||
// 创建交易上下文; | |||
// 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; | |||
LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); | |||
// 处理交易; | |||
resp = handleTx(request, txCtx); | |||
resp = handleTx(reqExt, txCtx); | |||
LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
@@ -99,10 +117,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
"Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (BlockRollbackException e) { | |||
// 抛弃发生处理异常的交易请求; | |||
// resp = discard(request, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); | |||
// 发生区块级别的处理异常,向上重新抛出异常进行处理,整个区块可能被丢弃; | |||
LOGGER.error(String.format( | |||
"Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
@@ -116,12 +133,79 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} finally { | |||
// 清空交易的用户安全策略; | |||
SecurityContext.removeContextUsersPolicy(); | |||
} | |||
responseList.add(resp); | |||
return resp; | |||
} | |||
/** | |||
* 执行安全验证; | |||
*/ | |||
private void checkSecurity(SecurityPolicy securityPolicy) { | |||
// 验证节点和终端身份的合法性; | |||
// 多重身份签署的必须全部身份都合法; | |||
securityPolicy.checkEndpointValidity(MultiIDsPolicy.ALL); | |||
securityPolicy.checkNodeValidity(MultiIDsPolicy.ALL); | |||
// 验证参与方节点是否具有核准交易的权限; | |||
securityPolicy.checkNodePermission(LedgerPermission.APPROVE_TX, MultiIDsPolicy.AT_LEAST_ONE); | |||
} | |||
private void checkRequest(TransactionRequestExtension reqExt) { | |||
// TODO: 把验签和创建交易并行化; | |||
checkTxContentHash(reqExt); | |||
checkEndpointSignatures(reqExt); | |||
checkNodeSignatures(reqExt); | |||
} | |||
private void checkTxContentHash(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 checkNodeSignatures(TransactionRequestExtension request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
Collection<Credential> nodes = request.getNodes(); | |||
if (nodes != null) { | |||
for (Credential node : nodes) { | |||
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); | |||
} | |||
} | |||
} | |||
} | |||
private void checkEndpointSignatures(TransactionRequestExtension request) { | |||
TransactionContent txContent = request.getTransactionContent(); | |||
Collection<Credential> endpoints = request.getEndpoints(); | |||
if (endpoints != null) { | |||
for (Credential endpoint : endpoints) { | |||
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); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* 处理交易;<br> | |||
* | |||
@@ -131,23 +215,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
* @param txCtx | |||
* @return | |||
*/ | |||
private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) { | |||
private TransactionResponse handleTx(TransactionRequestExtension request, LedgerTransactionContext txCtx) { | |||
TransactionState result; | |||
List<OperationResult> operationResults = new ArrayList<>(); | |||
try { | |||
LedgerDataSet dataset = txCtx.getDataSet(); | |||
TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); | |||
// TODO: 验证签名者的有效性; | |||
for (Bytes edpAddr : reqCtx.getEndpoints()) { | |||
if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { | |||
throw new LedgerException("The endpoint signer[" + edpAddr + "] was not registered!"); | |||
} | |||
} | |||
for (Bytes edpAddr : reqCtx.getNodes()) { | |||
if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { | |||
throw new LedgerException("The node signer[" + edpAddr + "] was not registered!"); | |||
} | |||
} | |||
LedgerDataset dataset = txCtx.getDataset(); | |||
// 执行操作; | |||
Operation[] ops = request.getTransactionContent().getOperations(); | |||
@@ -157,14 +229,14 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
// assert; Instance of operation are one of User related operations or | |||
// DataAccount related operations; | |||
OperationHandle hdl = opHandles.getHandle(operation.getClass()); | |||
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); | |||
hdl.process(operation, dataset, request, ledgerQueryer, this, ledgerService); | |||
} | |||
}; | |||
OperationHandle opHandle; | |||
int opIndex = 0; | |||
for (Operation op : ops) { | |||
opHandle = opHandles.getHandle(op.getClass()); | |||
BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, | |||
BytesValue opResult = opHandle.process(op, dataset, request, ledgerQueryer, handleContext, | |||
ledgerService); | |||
if (opResult != null) { | |||
operationResults.add(new OperationResultData(opIndex, opResult)); | |||
@@ -183,6 +255,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (BlockRollbackException e) { | |||
// 回滚整个区块; | |||
result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; | |||
txCtx.rollback(); | |||
LOGGER.error( | |||
@@ -201,17 +274,27 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
result = TransactionState.USER_DOES_NOT_EXIST; | |||
} else if (e instanceof ContractDoesNotExistException) { | |||
result = TransactionState.CONTRACT_DOES_NOT_EXIST; | |||
} else if (e instanceof ParticipantDoesNotExistException) { | |||
result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; | |||
} | |||
txCtx.discardAndCommit(result, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to ledger exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
"Due to ledger exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (LedgerSecurityException e) { | |||
// TODO: 识别更详细的异常类型以及执行对应的处理; | |||
result = TransactionState.REJECTED_BY_SECURITY_POLICY; | |||
txCtx.discardAndCommit(result, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to ledger security exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} catch (Exception e) { | |||
result = TransactionState.SYSTEM_ERROR; | |||
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); | |||
LOGGER.error(String.format( | |||
"Due to system exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
"Due to system exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
e.getMessage()), e); | |||
} |
@@ -1,16 +1,12 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.service.TransactionBatchProcess; | |||
import com.jd.blockchain.service.TransactionEngine; | |||
@@ -44,9 +40,15 @@ public class TransactionEngineImpl implements TransactionEngine { | |||
LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | |||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerBlock); | |||
batch = new InnerTransactionBatchProcessor(ledgerHash, newBlockEditor, previousBlockDataset, opHdlRegs, | |||
ledgerService, ledgerBlock.getHeight()); | |||
LedgerDataQuery previousBlockDataset = ledgerRepo.getDataSet(ledgerBlock); | |||
LedgerAdminDataQuery previousAdminDataset = previousBlockDataset.getAdminDataset(); | |||
LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl( | |||
previousAdminDataset.getAdminInfo().getRolePrivileges(), | |||
previousAdminDataset.getAdminInfo().getUserRoles(), previousAdminDataset.getParticipantDataset(), | |||
previousBlockDataset.getUserAccountSet()); | |||
batch = new InnerTransactionBatchProcessor(ledgerHash, securityManager, newBlockEditor, previousBlockDataset, | |||
opHdlRegs, ledgerService, ledgerBlock.getHeight()); | |||
batchs.put(ledgerHash, batch); | |||
return batch; | |||
} | |||
@@ -69,19 +71,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, | |||
LedgerService ledgerService, long blockHeight) { | |||
super(newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||
public InnerTransactionBatchProcessor(HashDigest ledgerHash, LedgerSecurityManager securityManager, | |||
LedgerEditor newBlockEditor, LedgerDataQuery previousBlockDataset, | |||
OperationHandleRegisteration opHandles, LedgerService ledgerService, long blockHeight) { | |||
super(securityManager, newBlockEditor, previousBlockDataset, opHandles, ledgerService); | |||
this.ledgerHash = ledgerHash; | |||
this.blockHeight = blockHeight; | |||
} |
@@ -1,70 +0,0 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Set; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 交易请求上下文; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionRequestContext { | |||
/** | |||
* 交易请求; | |||
* | |||
* @return | |||
*/ | |||
TransactionRequest getRequest(); | |||
/** | |||
* 签名发起请求的终端用户的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getEndpoints(); | |||
/** | |||
* 签名发起请求的节点的地址列表; | |||
* | |||
* @return | |||
*/ | |||
Set<Bytes> getNodes(); | |||
/** | |||
* 请求的终端发起人列表中是否包含指定地址的终端用户; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsEndpoint(Bytes address); | |||
/** | |||
* 请求的经手节点列表中是否包含指定地址的节点; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
boolean containsNode(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的终端的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getEndpointSignature(Bytes address); | |||
/** | |||
* 获取交易请求中指定地址的节点的签名; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
DigitalSignature getNodeSignature(Bytes address); | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -6,6 +6,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
@@ -153,6 +154,10 @@ public class TransactionSet implements Transactional, MerkleProvable { | |||
public boolean isReadonly() { | |||
return txSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
txSet.setReadonly(); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.LedgerDataSnapshot; |
@@ -0,0 +1,31 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface UserAccountQuery { | |||
AccountHeader[] getAccounts(int fromIndex, int count); | |||
/** | |||
* 返回用户总数; | |||
* | |||
* @return | |||
*/ | |||
long getTotalCount(); | |||
HashDigest getRootHash(); | |||
MerkleProof getProof(Bytes key); | |||
UserAccount getUser(String address); | |||
UserAccount getUser(Bytes address); | |||
boolean contains(Bytes address); | |||
UserAccount getUser(Bytes address, long version); | |||
} |
@@ -5,6 +5,7 @@ import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -14,7 +15,7 @@ import com.jd.blockchain.utils.Transactional; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccountSet implements Transactional, MerkleProvable { | |||
public class UserAccountSet implements Transactional, MerkleProvable, UserAccountQuery { | |||
private AccountSet accountSet; | |||
@@ -30,6 +31,7 @@ public class UserAccountSet implements Transactional, MerkleProvable { | |||
accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getAccounts(int fromIndex, int count) { | |||
return accountSet.getAccounts(fromIndex,count); | |||
} | |||
@@ -39,6 +41,7 @@ public class UserAccountSet implements Transactional, MerkleProvable { | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotalCount() { | |||
return accountSet.getTotalCount(); | |||
} | |||
@@ -46,6 +49,10 @@ public class UserAccountSet implements Transactional, MerkleProvable { | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
@@ -57,19 +64,23 @@ public class UserAccountSet implements Transactional, MerkleProvable { | |||
return accountSet.getProof(key); | |||
} | |||
@Override | |||
public UserAccount getUser(String address) { | |||
return getUser(Bytes.fromBase58(address)); | |||
} | |||
@Override | |||
public UserAccount getUser(Bytes address) { | |||
BaseAccount baseAccount = accountSet.getAccount(address); | |||
return new UserAccount(baseAccount); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public UserAccount getUser(Bytes address, long version) { | |||
BaseAccount baseAccount = accountSet.getAccount(address, version); | |||
return new UserAccount(baseAccount); | |||
@@ -0,0 +1,196 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Collection; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AuthorizationException; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.RoleSet; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.UserRoles; | |||
import com.jd.blockchain.ledger.UserRolesSettings; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
/** | |||
* User-Role authorization data set; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserRoleDataset implements Transactional, MerkleProvable, UserRolesSettings { | |||
private MerkleDataSet dataset; | |||
public UserRoleDataset(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage verStorage) { | |||
dataset = new MerkleDataSet(cryptoSetting, prefix, exPolicyStorage, verStorage); | |||
} | |||
public UserRoleDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return dataset.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return dataset.getProof(key); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return dataset.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
dataset.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
dataset.cancel(); | |||
} | |||
@Override | |||
public long getUserCount() { | |||
return dataset.getDataCount(); | |||
} | |||
/** | |||
* 加入新的用户角色授权; <br> | |||
* | |||
* 如果该用户的授权已经存在,则引发 {@link LedgerException} 异常; | |||
* | |||
* @param userAddress | |||
* @param rolesPolicy | |||
* @param roles | |||
*/ | |||
@Override | |||
public void addUserRoles(Bytes userAddress, RolesPolicy rolesPolicy, String... roles) { | |||
UserRoles roleAuth = new UserRoles(userAddress, -1, rolesPolicy); | |||
roleAuth.addRoles(roles); | |||
long nv = setUserRolesAuthorization(roleAuth); | |||
if (nv < 0) { | |||
throw new AuthorizationException("Roles authorization of User[" + userAddress + "] already exists!"); | |||
} | |||
} | |||
/** | |||
* 加入新的用户角色授权; <br> | |||
* | |||
* 如果该用户的授权已经存在,则引发 {@link LedgerException} 异常; | |||
* | |||
* @param userAddress | |||
* @param rolesPolicy | |||
* @param roles | |||
*/ | |||
@Override | |||
public void addUserRoles(Bytes userAddress, RolesPolicy rolesPolicy, Collection<String> roles) { | |||
UserRoles roleAuth = new UserRoles(userAddress, -1, rolesPolicy); | |||
roleAuth.addRoles(roles); | |||
long nv = setUserRolesAuthorization(roleAuth); | |||
if (nv < 0) { | |||
throw new AuthorizationException("Roles authorization of User[" + userAddress + "] already exists!"); | |||
} | |||
} | |||
/** | |||
* 设置用户角色授权; <br> | |||
* 如果版本校验不匹配,则返回 -1; | |||
* | |||
* @param userRoles | |||
* @return | |||
*/ | |||
private long setUserRolesAuthorization(UserRoles userRoles) { | |||
if (userRoles.getRoleCount() > MAX_ROLES_PER_USER) { | |||
throw new AuthorizationException("The number of roles exceeds the maximum range!"); | |||
} | |||
byte[] rolesetBytes = BinaryProtocol.encode(userRoles, RoleSet.class); | |||
return dataset.setValue(userRoles.getUserAddress(), rolesetBytes, userRoles.getVersion()); | |||
} | |||
/** | |||
* 更新用户角色授权; <br> | |||
* 如果指定用户的授权不存在,或者版本不匹配,则引发 {@link LedgerException} 异常; | |||
* | |||
* @param userRoles | |||
*/ | |||
@Override | |||
public void updateUserRoles(UserRoles userRoles) { | |||
long nv = setUserRolesAuthorization(userRoles); | |||
if (nv < 0) { | |||
throw new AuthorizationException("Update to roles of user[" + userRoles.getUserAddress() | |||
+ "] failed due to wrong version[" + userRoles.getVersion() + "] !"); | |||
} | |||
} | |||
/** | |||
* 设置用户的角色; <br> | |||
* 如果用户的角色授权不存在,则创建新的授权; | |||
* | |||
* @param userAddress 用户; | |||
* @param policy 角色策略; | |||
* @param roles 角色列表; | |||
* @return | |||
*/ | |||
@Override | |||
public long setRoles(Bytes userAddress, RolesPolicy policy, String... roles) { | |||
UserRoles userRoles = getUserRoles(userAddress); | |||
if (userRoles == null) { | |||
userRoles = new UserRoles(userAddress, -1, policy); | |||
} | |||
userRoles.setPolicy(policy); | |||
userRoles.setRoles(roles); | |||
return setUserRolesAuthorization(userRoles); | |||
} | |||
/** | |||
* 查询角色授权; | |||
* | |||
* <br> | |||
* 如果不存在,则返回 null; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public UserRoles getUserRoles(Bytes userAddress) { | |||
// 只返回最新版本; | |||
VersioningKVEntry kv = dataset.getDataEntry(userAddress); | |||
if (kv == null) { | |||
return null; | |||
} | |||
RoleSet roleSet = BinaryProtocol.decode(kv.getValue()); | |||
return new UserRoles(userAddress, kv.getVersion(), roleSet); | |||
} | |||
@Override | |||
public UserRoles[] getUserRoles() { | |||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); | |||
UserRoles[] pns = new UserRoles[kvEntries.length]; | |||
RoleSet roleset; | |||
for (int i = 0; i < pns.length; i++) { | |||
roleset = BinaryProtocol.decode(kvEntries[i].getValue()); | |||
pns[i] = new UserRoles(kvEntries[i].getKey(), kvEntries[i].getVersion(), roleset); | |||
} | |||
return pns; | |||
} | |||
@Override | |||
public boolean isReadonly() { | |||
return dataset.isReadonly(); | |||
} | |||
} |
@@ -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,73 @@ | |||
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.LedgerDataQuery; | |||
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 Class<?> getOperationType() { | |||
return SUPPORTED_OPERATION_TYPE; | |||
} | |||
@Override | |||
public final BytesValue process(Operation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(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, | |||
LedgerDataQuery previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl.handles; | |||
package com.jd.blockchain.ledger.core.handles; | |||
import org.springframework.stereotype.Service; | |||
@@ -8,30 +8,48 @@ import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.core.ContractAccount; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.ContractAccountQuery; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.MultiIDsPolicy; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
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; | |||
@Service | |||
public abstract class AbtractContractEventHandle implements OperationHandle { | |||
public abstract class AbtractContractEventSendOperationHandle implements OperationHandle { | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return ContractEventSendOperation.class.isAssignableFrom(operationType); | |||
public Class<?> getOperationType() { | |||
return ContractEventSendOperation.class; | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
public BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataQuery previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(TransactionPermission.CONTRACT_OPERATION, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||
return doProcess(requestContext, contractOP, newBlockDataset, previousBlockDataset, opHandleContext, | |||
ledgerService); | |||
} | |||
private BytesValue doProcess(TransactionRequestExtension request, ContractEventSendOperation contractOP, | |||
LedgerDataset newBlockDataset, LedgerDataQuery previousBlockDataset, OperationHandleContext opHandleContext, | |||
LedgerService ledgerService) { | |||
// 先从账本校验合约的有效性; | |||
// 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; | |||
ContractAccountSet contractSet = previousBlockDataset.getContractAccountSet(); | |||
ContractAccountQuery contractSet = previousBlockDataset.getContractAccountset(); | |||
if (!contractSet.contains(contractOP.getContractAddress())) { | |||
throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
@@ -50,19 +68,17 @@ public abstract class AbtractContractEventHandle implements OperationHandle { | |||
// 创建合约上下文; | |||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | |||
request.getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(request) | |||
.setLedgerContext(ledgerContext); | |||
// 装载合约; | |||
ContractCode contractCode = loadContractCode(contract); | |||
// 处理合约事件; | |||
return contractCode.processEvent(localContractEventContext); | |||
} | |||
protected abstract ContractCode loadContractCode(ContractAccount contract); | |||
protected abstract ContractCode loadContractCode(ContractAccount contract); | |||
} |
@@ -0,0 +1,37 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
public class ContractCodeDeployOperationHandle extends AbstractLedgerOperationHandle<ContractCodeDeployOperation> { | |||
public ContractCodeDeployOperationHandle() { | |||
super(ContractCodeDeployOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(ContractCodeDeployOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// TODO: 校验合约代码的正确性; | |||
// TODO: 请求者应该提供合约账户的公钥签名,以确保注册人对注册的地址和公钥具有合法的使用权; | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.UPGRADE_CONTRACT, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; | |||
newBlockDataset.getContractAccountset().deploy(contractOP.getContractID().getAddress(), | |||
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.ledger.core.impl.handles; | |||
package com.jd.blockchain.ledger.core.handles; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -6,7 +6,7 @@ import java.util.List; | |||
import com.jd.blockchain.contract.LedgerContext; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.transaction.BlockchainQueryService; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; | |||
import com.jd.blockchain.transaction.DataAccountRegisterOperationBuilder; | |||
@@ -38,6 +38,11 @@ public class ContractLedgerContext implements LedgerContext { | |||
public LedgerInfo getLedger(HashDigest ledgerHash) { | |||
return innerQueryService.getLedger(ledgerHash); | |||
} | |||
@Override | |||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||
return innerQueryService.getLedgerAdminInfo(ledgerHash); | |||
} | |||
@Override | |||
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { |
@@ -0,0 +1,47 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.DataAccountDoesNotExistException; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; | |||
import com.jd.blockchain.ledger.DataVersionConflictException; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccountKVSetOperationHandle extends AbstractLedgerOperationHandle<DataAccountKVSetOperation> { | |||
public DataAccountKVSetOperationHandle() { | |||
super(DataAccountKVSetOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(DataAccountKVSetOperation kvWriteOp, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.WRITE_DATA_ACCOUNT, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
DataAccount account = newBlockDataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); | |||
if (account == null) { | |||
throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); | |||
} | |||
KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); | |||
long v = -1; | |||
for (KVWriteEntry kvw : writeSet) { | |||
v = account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); | |||
if (v < 0) { | |||
throw new DataVersionConflictException(); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
public class DataAccountRegisterOperationHandle extends AbstractLedgerOperationHandle<DataAccountRegisterOperation> { | |||
public DataAccountRegisterOperationHandle() { | |||
super(DataAccountRegisterOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(DataAccountRegisterOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// TODO: 请求者应该提供数据账户的公钥签名,以更好地确保注册人对该地址和公钥具有合法使用权; | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.REGISTER_DATA_ACCOUNT, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; | |||
BlockchainIdentity bid = dataAccountRegOp.getAccountID(); | |||
newBlockDataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); | |||
} | |||
} |
@@ -1,13 +1,13 @@ | |||
package com.jd.blockchain.ledger.core.impl.handles; | |||
package com.jd.blockchain.ledger.core.handles; | |||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.contract.engine.ContractEngine; | |||
import com.jd.blockchain.contract.engine.ContractServiceProviders; | |||
import com.jd.blockchain.ledger.core.ContractAccount; | |||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||
public class JVMContractEventSendOperationHandle extends AbtractContractEventHandle { | |||
public class JVMContractEventSendOperationHandle extends AbtractContractEventSendOperationHandle { | |||
private static final ContractEngine JVM_ENGINE; | |||
@@ -26,12 +26,4 @@ public class JVMContractEventSendOperationHandle extends AbtractContractEventHan | |||
return contractCode; | |||
} | |||
// @Override | |||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, | |||
// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, | |||
// OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
} |
@@ -0,0 +1,27 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
public class LedgerInitOperationHandle implements OperationHandle { | |||
@Override | |||
public Class<?> getOperationType() { | |||
return LedgerInitOperation.class; | |||
} | |||
@Override | |||
public BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, | |||
LedgerDataQuery previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 对初始化操作不需要做任何处理; | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolePrivileges; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation.RolePrivilegeEntry; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
public class RolesConfigureOperationHandle extends AbstractLedgerOperationHandle<RolesConfigureOperation> { | |||
public RolesConfigureOperationHandle() { | |||
super(RolesConfigureOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(RolesConfigureOperation operation, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension request, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.CONFIGURE_ROLES, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
RolePrivilegeEntry[] rpcfgs = operation.getRoles(); | |||
RolePrivilegeSettings rpSettings = newBlockDataset.getAdminDataset().getRolePrivileges(); | |||
if (rpcfgs != null) { | |||
for (RolePrivilegeEntry rpcfg : rpcfgs) { | |||
RolePrivileges rp = rpSettings.getRolePrivilege(rpcfg.getRoleName()); | |||
if (rp == null) { | |||
rpSettings.addRolePrivilege(rpcfg.getRoleName(), rpcfg.getEnableLedgerPermissions(), | |||
rpcfg.getEnableTransactionPermissions()); | |||
} else { | |||
rp.enable(rpcfg.getEnableLedgerPermissions()); | |||
rp.enable(rpcfg.getEnableTransactionPermissions()); | |||
rp.disable(rpcfg.getDisableLedgerPermissions()); | |||
rp.disable(rpcfg.getDisableTransactionPermissions()); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation.UserRolesEntry; | |||
import com.jd.blockchain.ledger.UserRoles; | |||
import com.jd.blockchain.ledger.UserRolesSettings; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class UserAuthorizeOperationHandle extends AbstractLedgerOperationHandle<UserAuthorizeOperation> { | |||
public UserAuthorizeOperationHandle() { | |||
super(UserAuthorizeOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(UserAuthorizeOperation operation, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension request, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.CONFIGURE_ROLES, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
UserRolesEntry[] urcfgs = operation.getUserRolesAuthorizations(); | |||
UserRolesSettings urSettings = newBlockDataset.getAdminDataset().getUserRoles(); | |||
RolePrivilegeSettings rolesSettings = newBlockDataset.getAdminDataset().getRolePrivileges(); | |||
if (urcfgs != null) { | |||
for (UserRolesEntry urcfg : urcfgs) { | |||
// | |||
String[] authRoles = urcfg.getAuthorizedRoles(); | |||
List<String> validRoles = new ArrayList<String>(); | |||
if (authRoles != null) { | |||
for (String r : authRoles) { | |||
if (rolesSettings.contains(r)) { | |||
validRoles.add(r); | |||
} | |||
} | |||
} | |||
for (Bytes address : urcfg.getUserAddresses()) { | |||
UserRoles ur = urSettings.getUserRoles(address); | |||
if (ur == null) { | |||
// 这是新的授权; | |||
RolesPolicy policy = urcfg.getPolicy(); | |||
if (policy == null) { | |||
policy = RolesPolicy.UNION; | |||
} | |||
urSettings.addUserRoles(address, policy, validRoles); | |||
} else { | |||
// 更改之前的授权; | |||
ur.addRoles(validRoles); | |||
ur.removeRoles(urcfg.getUnauthorizedRoles()); | |||
// 如果请求中设置了策略,才进行更新; | |||
RolesPolicy policy = urcfg.getPolicy(); | |||
if (policy != null) { | |||
ur.setPolicy(policy); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
package com.jd.blockchain.ledger.core.handles; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
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.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.SecurityContext; | |||
import com.jd.blockchain.ledger.core.SecurityPolicy; | |||
import com.jd.blockchain.ledger.core.TransactionRequestExtension; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class UserRegisterOperationHandle extends AbstractLedgerOperationHandle<UserRegisterOperation> { | |||
public UserRegisterOperationHandle() { | |||
super(UserRegisterOperation.class); | |||
} | |||
@Override | |||
protected void doProcess(UserRegisterOperation op, LedgerDataset newBlockDataset, | |||
TransactionRequestExtension requestContext, LedgerDataQuery previousBlockDataset, | |||
OperationHandleContext handleContext, LedgerService ledgerService) { | |||
// 权限校验; | |||
SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); | |||
securityPolicy.checkEndpointPermission(LedgerPermission.REGISTER_USER, MultiIDsPolicy.AT_LEAST_ONE); | |||
// 操作账本; | |||
UserRegisterOperation userRegOp = (UserRegisterOperation) op; | |||
BlockchainIdentity bid = userRegOp.getUserID(); | |||
Bytes userAddress = bid.getAddress(); | |||
newBlockDataset.getUserAccountSet().register(userAddress, bid.getPubKey()); | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
package com.jd.blockchain.ledger.core.impl; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | |||