# 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; | |||