@@ -121,12 +121,16 @@ public interface DataCodes { | |||
public static final int ACCOUNT_HEADER = 0x710; | |||
public static final int USER = 0x800; | |||
public static final int USER_ACCOUNT_HEADER = 0x800; | |||
public static final int USER_INFO = 0x801; | |||
public static final int DATA = 0x900; | |||
// contract related; | |||
public static final int CONTRACT = 0xA00; | |||
public static final int CONTRACT_ACCOUNT_HEADER = 0xA00; | |||
public static final int CONTRACT_INFO = 0xA01; | |||
// ...0xA19 | |||
public static final int HASH = 0xB00; | |||
@@ -21,8 +21,6 @@ class DynamicDataContract implements InvocationHandler { | |||
private DataContractEncoderImpl contractEncoder; | |||
// private BytesSlice contractBytes; | |||
// 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段; | |||
private BytesSlices[] dataSlices; | |||
@@ -1,7 +1,7 @@ | |||
package com.jd.blockchain.contract; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
@Contract | |||
public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||
@@ -24,7 +24,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||
@Override | |||
@ContractEvent(name = "read-key") | |||
public String read(String address, String key) { | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); | |||
if (kvDataEntries != null && kvDataEntries.length == 1) { | |||
return kvDataEntries[0].getValue().toString(); | |||
@@ -35,7 +35,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||
@Override | |||
@ContractEvent(name = "version-key") | |||
public Long readVersion(String address, String key) { | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); | |||
if (kvDataEntries != null && kvDataEntries.length == 1) { | |||
return kvDataEntries[0].getVersion(); | |||
@@ -2,7 +2,7 @@ package com.jd.blockchain.contract; | |||
import com.alibaba.fastjson.JSON; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVDataVO; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
@@ -14,7 +14,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||
@Override | |||
public String create(String address, String account, long money) { | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
// 肯定有返回值,但若不存在则返回version=-1 | |||
if (kvDataEntries != null && kvDataEntries.length > 0) { | |||
long currVersion = kvDataEntries[0].getVersion(); | |||
@@ -32,13 +32,13 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||
@Override | |||
public String transfer(String address, String from, String to, long money) { | |||
// 首先查询余额 | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); | |||
if (kvDataEntries == null || kvDataEntries.length != 2) { | |||
throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | |||
} else { | |||
// 判断from账号中钱数量是否足够 | |||
long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | |||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||
for (TypedKVEntry kvDataEntry : kvDataEntries) { | |||
if (kvDataEntry.getKey().equals(from)) { | |||
fromMoney = (long) kvDataEntry.getValue(); | |||
fromVersion = kvDataEntry.getVersion(); | |||
@@ -62,7 +62,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||
@Override | |||
public long read(String address, String account) { | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
return -1; | |||
} | |||
@@ -71,7 +71,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||
@Override | |||
public String readAll(String address, String account) { | |||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
// 获取最新的版本号 | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
return ""; | |||
@@ -91,7 +91,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||
KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); | |||
KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); | |||
TypedKVEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); | |||
return JSON.toJSONString(allEntries); | |||
} | |||
@@ -23,9 +23,9 @@ import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.gateway.PeerService; | |||
import com.jd.blockchain.gateway.service.DataRetrievalService; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
@@ -252,7 +252,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") | |||
@Override | |||
public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address) { | |||
return peerService.getQueryService().getDataAccount(ledgerHash, address); | |||
@@ -261,7 +261,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
@PathVariable("address") String address, @RequestParam("keys") String... keys) { | |||
return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); | |||
} | |||
@@ -269,7 +269,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
@PathVariable("address") String address, @RequestBody KVInfoVO kvInfoVO) { | |||
return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); | |||
} | |||
@@ -277,7 +277,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||
@PathVariable("address") String address, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
@@ -594,7 +594,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
*/ | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") | |||
@Override | |||
public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
return peerService.getQueryService().getUsers(ledgerHash, fromIndex, count); | |||
@@ -602,7 +602,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") | |||
@Override | |||
public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
return peerService.getQueryService().getDataAccounts(ledgerHash, fromIndex, count); | |||
@@ -610,7 +610,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") | |||
@Override | |||
public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
return peerService.getQueryService().getContractAccounts(ledgerHash, fromIndex, count); | |||
@@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
@@ -19,7 +19,7 @@ public interface AccountAccessPolicy { | |||
* @param account | |||
* @return Return true if it satisfies this policy, or false if it doesn't; | |||
*/ | |||
boolean checkDataWriting(AccountHeader account); | |||
boolean checkDataWriting(BlockchainIdentity account); | |||
boolean checkRegistering(Bytes address, PubKey pubKey); | |||
@@ -0,0 +1,45 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.Account; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.HashProof; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Dataset; | |||
public class AccountDecorator implements Account, HashProvable, MerkleSnapshot{ | |||
private CompositeAccount mklAccount; | |||
public AccountDecorator(CompositeAccount mklAccount) { | |||
this.mklAccount = mklAccount; | |||
} | |||
protected Dataset<String, TypedValue> getHeaders() { | |||
return mklAccount.getHeaders(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return mklAccount.getRootHash(); | |||
} | |||
@Override | |||
public HashProof getProof(Bytes key) { | |||
return mklAccount.getProof(key); | |||
} | |||
@Override | |||
public BlockchainIdentity getID() { | |||
return mklAccount.getID(); | |||
} | |||
@Override | |||
public Dataset<String, TypedValue> getDataset() { | |||
return mklAccount.getDataset(); | |||
} | |||
} |
@@ -1,12 +1,11 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface AccountQuery<T> extends MerkleProvable { | |||
AccountHeader[] getHeaders(int fromIndex, int count); | |||
/** | |||
* 返回总数; | |||
* | |||
@@ -14,7 +13,15 @@ public interface AccountQuery<T> extends MerkleProvable { | |||
*/ | |||
long getTotal(); | |||
BlockchainIdentity[] getHeaders(int fromIndex, int count); | |||
boolean contains(Bytes address); | |||
/** | |||
* get proof of specified account; | |||
*/ | |||
@Override | |||
MerkleProof getProof(Bytes address); | |||
/** | |||
* 返回账户实例; | |||
@@ -0,0 +1,12 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.Account; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.utils.Dataset; | |||
public interface CompositeAccount extends Account, MerkleSnapshot, HashProvable{ | |||
Dataset<String, TypedValue> getHeaders(); | |||
} |
@@ -1,81 +1,72 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
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.ledger.TypedValue; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractAccount implements ContractInfo { | |||
public class ContractAccount extends AccountDecorator implements ContractInfo { | |||
private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR); | |||
private static final String CONTRACT_INFO_PREFIX = "INFO" + LedgerConsts.KEY_SEPERATOR; | |||
private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); | |||
private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; | |||
private MerkleAccount accBase; | |||
public ContractAccount(MerkleAccount accBase) { | |||
this.accBase = accBase; | |||
public ContractAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return accBase.getAddress(); | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return accBase.getPubKey(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accBase.getRootHash(); | |||
return getID().getPubKey(); | |||
} | |||
public MerkleProof getChaincodeProof() { | |||
return accBase.getProof(CHAIN_CODE_KEY); | |||
} | |||
public MerkleProof getPropertyProof(Bytes key) { | |||
return accBase.getProof(encodePropertyKey(key)); | |||
} | |||
// public MerkleProof getChaincodeProof() { | |||
// return getHeaders().getProof(CHAIN_CODE_KEY); | |||
// } | |||
// | |||
// public MerkleProof getPropertyProof(Bytes key) { | |||
// return getHeaders().getProof(encodePropertyKey(key)); | |||
// } | |||
public long setChaincode(byte[] chaincode, long version) { | |||
BytesValue bytesValue = BytesData.fromBytes(chaincode); | |||
return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version); | |||
TypedValue bytesValue = TypedValue.fromBytes(chaincode); | |||
return getHeaders().setValue(CHAIN_CODE_KEY, bytesValue, version); | |||
} | |||
public byte[] getChainCode() { | |||
return accBase.getBytes(CHAIN_CODE_KEY).getValue().toBytes(); | |||
return getHeaders().getValue(CHAIN_CODE_KEY).getBytes().toBytes(); | |||
} | |||
public byte[] getChainCode(long version) { | |||
return accBase.getBytes(CHAIN_CODE_KEY, version).getValue().toBytes(); | |||
return getHeaders().getValue(CHAIN_CODE_KEY, version).getBytes().toBytes(); | |||
} | |||
public long getChaincodeVersion() { | |||
return accBase.getVersion(CHAIN_CODE_KEY); | |||
return getHeaders().getVersion(CHAIN_CODE_KEY); | |||
} | |||
public long setProperty(Bytes key, String value, long version) { | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
return accBase.setBytes(encodePropertyKey(key), bytesValue, version); | |||
public long setProperty(String key, String value, long version) { | |||
TypedValue bytesValue = TypedValue.fromText(value); | |||
return getHeaders().setValue(encodePropertyKey(key), bytesValue, version); | |||
} | |||
public String getProperty(Bytes key) { | |||
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key)); | |||
return BytesData.toText(bytesValue); | |||
public String getProperty(String key) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key)); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
public String getProperty(Bytes key, long version) { | |||
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version); | |||
return BytesData.toText(bytesValue); | |||
public String getProperty(String key, long version) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key), version); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
private Bytes encodePropertyKey(Bytes key) { | |||
private String encodePropertyKey(String key) { | |||
return CONTRACT_INFO_PREFIX.concat(key); | |||
} | |||
@@ -2,7 +2,7 @@ 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.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
@@ -17,17 +17,18 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
@@ -66,7 +67,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
@Override | |||
public ContractAccount getAccount(Bytes address) { | |||
MerkleAccount accBase = accountSet.getAccount(address); | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
return new ContractAccount(accBase); | |||
} | |||
@@ -77,7 +78,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
@Override | |||
public ContractAccount getAccount(Bytes address, long version) { | |||
MerkleAccount accBase = accountSet.getAccount(address, version); | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new ContractAccount(accBase); | |||
} | |||
@@ -92,7 +93,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
*/ | |||
public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { | |||
// TODO: 校验和记录合约地址签名; | |||
MerkleAccount accBase = accountSet.register(address, pubKey); | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
contractAcc.setChaincode(chaincode, -1); | |||
return contractAcc; | |||
@@ -107,7 +108,7 @@ public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
* @return 返回链码的新版本号; | |||
*/ | |||
public long update(Bytes address, byte[] chaincode, long version) { | |||
MerkleAccount accBase = accountSet.getAccount(address); | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
return contractAcc.setChaincode(chaincode, version); | |||
} | |||
@@ -1,268 +1,234 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
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 { | |||
private MerkleAccount baseAccount; | |||
public DataAccount(MerkleAccount accBase) { | |||
this.baseAccount = accBase; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return baseAccount.getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return baseAccount.getPubKey(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return baseAccount.getRootHash(); | |||
} | |||
/** | |||
* 返回指定数据的存在性证明; | |||
*/ | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return baseAccount.getProof(key); | |||
} | |||
public class DataAccount extends AccountDecorator { | |||
public DataAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * 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 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> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, BytesValue value, long version) { | |||
// return super.getDataset().setValue(key, value, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * 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 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> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromText(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * 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 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> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromBytes(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(String key) { | |||
// return baseAccount.getVersion(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(Bytes key) { | |||
// return baseAccount.getVersion(key); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key) { | |||
// return baseAccount.getValue(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key) { | |||
// return baseAccount.getValue(key); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key, long version) { | |||
// return baseAccount.getValue(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key, long version) { | |||
// return baseAccount.getValue(key, version); | |||
// } | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
* | |||
* The value of the key will be updated only if it's latest version equals the | |||
* specified version argument. <br> | |||
* If the key doesn't exist, the version checking will be ignored, and key will | |||
* be created with a new sequence number as id. <br> | |||
* It also could specify the version argument to -1 to ignore the version | |||
* checking. | |||
* <p> | |||
* 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 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> | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
*/ | |||
public long setBytes(Bytes key, BytesValue value, long version) { | |||
return baseAccount.setBytes(key, value, version); | |||
} | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
* | |||
* The value of the key will be updated only if it's latest version equals the | |||
* specified version argument. <br> | |||
* If the key doesn't exist, the version checking will be ignored, and key will | |||
* be created with a new sequence number as id. <br> | |||
* It also could specify the version argument to -1 to ignore the version | |||
* checking. | |||
* <p> | |||
* 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 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> | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
*/ | |||
public long setBytes(Bytes key, String value, long version) { | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
return baseAccount.setBytes(key, bytesValue, version); | |||
} | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
* | |||
* The value of the key will be updated only if it's latest version equals the | |||
* specified version argument. <br> | |||
* If the key doesn't exist, the version checking will be ignored, and key will | |||
* be created with a new sequence number as id. <br> | |||
* It also could specify the version argument to -1 to ignore the version | |||
* checking. | |||
* <p> | |||
* 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 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> | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
*/ | |||
public long setBytes(Bytes key, byte[] value, long version) { | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
return baseAccount.setBytes(key, bytesValue, version); | |||
} | |||
/** | |||
* Return the latest version entry associated the specified key; If the key | |||
* doesn't exist, then return -1; | |||
* | |||
* @param key | |||
* @return | |||
*/ | |||
public long getDataVersion(String key) { | |||
return baseAccount.getVersion(Bytes.fromString(key)); | |||
} | |||
/** | |||
* Return the latest version entry associated the specified key; If the key | |||
* doesn't exist, then return -1; | |||
* | |||
* @param key | |||
* @return | |||
*/ | |||
public long getDataVersion(Bytes key) { | |||
return baseAccount.getVersion(key); | |||
} | |||
/** | |||
* return the latest version's value; | |||
* | |||
* @param key | |||
* @return return null if not exist; | |||
*/ | |||
public BytesValue getBytes(String key) { | |||
return baseAccount.getBytes(Bytes.fromString(key)); | |||
} | |||
/** | |||
* return the latest version's value; | |||
* | |||
* @param key | |||
* @return return null if not exist; | |||
*/ | |||
public BytesValue getBytes(Bytes key) { | |||
return baseAccount.getBytes(key); | |||
} | |||
/** | |||
* return the specified version's value; | |||
* | |||
* @param key | |||
* @param version | |||
* @return return null if not exist; | |||
*/ | |||
public BytesValue getBytes(String key, long version) { | |||
return baseAccount.getBytes(Bytes.fromString(key), version); | |||
} | |||
/** | |||
* return the specified version's value; | |||
* | |||
* @param key | |||
* @param version | |||
* @return return null if not exist; | |||
*/ | |||
public BytesValue getBytes(Bytes key, long version) { | |||
return baseAccount.getBytes(key, version); | |||
} | |||
/** | |||
* @param key | |||
* @param version | |||
* @return | |||
*/ | |||
public KVDataEntry getDataEntry(String key, long version) { | |||
return getDataEntry(Bytes.fromString(key), version); | |||
} | |||
/** | |||
* @param key | |||
* @param version | |||
* @return | |||
*/ | |||
public KVDataEntry getDataEntry(Bytes key, long version) { | |||
BytesValue value = baseAccount.getBytes(key, version); | |||
if (value == null) { | |||
return new KVDataObject(key.toUTF8String(), -1, null); | |||
}else { | |||
return new KVDataObject(key.toUTF8String(), version, value); | |||
} | |||
} | |||
/** | |||
* return the specified index's KVDataEntry; | |||
* | |||
* @param fromIndex | |||
* @param count | |||
* @return return null if not exist; | |||
*/ | |||
public KVDataEntry[] getDataEntries(int fromIndex, int count) { | |||
if (count == 0 || getDataEntriesTotalCount() == 0) { | |||
return null; | |||
} | |||
if (count == -1 || count > getDataEntriesTotalCount()) { | |||
fromIndex = 0; | |||
count = (int)getDataEntriesTotalCount(); | |||
} | |||
if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { | |||
fromIndex = 0; | |||
} | |||
KVDataEntry[] kvDataEntries = new KVDataEntry[count]; | |||
byte[] value; | |||
String key; | |||
long ver; | |||
for (int i = 0; i < count; i++) { | |||
value = baseAccount.dataset.getValuesAtIndex(fromIndex); | |||
key = baseAccount.dataset.getKeyAtIndex(fromIndex); | |||
ver = baseAccount.dataset.getVersion(key); | |||
BytesValue decodeData = BinaryProtocol.decode(value); | |||
kvDataEntries[i] = new KVDataObject(key, ver, decodeData); | |||
fromIndex++; | |||
} | |||
return kvDataEntries; | |||
} | |||
/** | |||
* return the dataAccount's kv total count; | |||
* | |||
* @param | |||
* @param | |||
* @return return total count; | |||
*/ | |||
public long getDataEntriesTotalCount() { | |||
if(baseAccount == null){ | |||
return 0; | |||
} | |||
return baseAccount.dataset.getDataCount(); | |||
} | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(String key, long version) { | |||
// return getDataEntry(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(Bytes key, long version) { | |||
// BytesValue value = baseAccount.getValue(key, version); | |||
// if (value == null) { | |||
// return new KVDataObject(key.toUTF8String(), -1, null); | |||
// }else { | |||
// return new KVDataObject(key.toUTF8String(), version, value); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * return the specified index's KVDataEntry; | |||
// * | |||
// * @param fromIndex | |||
// * @param count | |||
// * @return return null if not exist; | |||
// */ | |||
// | |||
// public KVDataEntry[] getDataEntries(int fromIndex, int count) { | |||
// if (count == 0 || getDataEntriesTotalCount() == 0) { | |||
// return null; | |||
// } | |||
// | |||
// if (count == -1 || count > getDataEntriesTotalCount()) { | |||
// fromIndex = 0; | |||
// count = (int)getDataEntriesTotalCount(); | |||
// } | |||
// | |||
// if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { | |||
// fromIndex = 0; | |||
// } | |||
// | |||
// KVDataEntry[] kvDataEntries = new KVDataEntry[count]; | |||
// byte[] value; | |||
// String key; | |||
// long ver; | |||
// for (int i = 0; i < count; i++) { | |||
// value = baseAccount.dataset.getValuesAtIndex(fromIndex); | |||
// key = baseAccount.dataset.getKeyAtIndex(fromIndex); | |||
// ver = baseAccount.dataset.getVersion(key); | |||
// BytesValue decodeData = BinaryProtocol.decode(value); | |||
// kvDataEntries[i] = new KVDataObject(key, ver, decodeData); | |||
// fromIndex++; | |||
// } | |||
// | |||
// return kvDataEntries; | |||
// } | |||
// | |||
// /** | |||
// * return the dataAccount's kv total count; | |||
// * | |||
// * @param | |||
// * @param | |||
// * @return return total count; | |||
// */ | |||
// public long getDataEntriesTotalCount() { | |||
// if(baseAccount == null){ | |||
// return 0; | |||
// } | |||
// return baseAccount.dataset.getDataCount(); | |||
// } | |||
} |
@@ -2,7 +2,7 @@ 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.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
@@ -17,17 +17,18 @@ public class DataAccountSet implements Transactional, DataAccountQuery { | |||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, prefix, exStorage, verStorage, readonly, accessPolicy); | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
@@ -64,7 +65,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { | |||
public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { | |||
// TODO: 未实现对地址签名的校验和记录; | |||
MerkleAccount accBase = accountSet.register(address, pubKey); | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
return new DataAccount(accBase); | |||
} | |||
@@ -82,7 +83,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { | |||
*/ | |||
@Override | |||
public DataAccount getAccount(Bytes address) { | |||
MerkleAccount accBase = accountSet.getAccount(address); | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
if (accBase == null) { | |||
return null; | |||
} | |||
@@ -91,7 +92,7 @@ public class DataAccountSet implements Transactional, DataAccountQuery { | |||
@Override | |||
public DataAccount getAccount(Bytes address, long version) { | |||
MerkleAccount accBase = accountSet.getAccount(address, version); | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new DataAccount(accBase); | |||
} | |||
@@ -1,13 +1,13 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class EmptyAccountSet<T> implements AccountQuery<T> { | |||
private static final AccountHeader[] EMPTY = {}; | |||
private static final BlockchainIdentity[] EMPTY = {}; | |||
@Override | |||
public HashDigest getRootHash() { | |||
@@ -20,7 +20,7 @@ public class EmptyAccountSet<T> implements AccountQuery<T> { | |||
} | |||
@Override | |||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return EMPTY; | |||
} | |||
@@ -0,0 +1,92 @@ | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//import com.jd.blockchain.crypto.HashDigest; | |||
//import com.jd.blockchain.ledger.AccountHeader; | |||
//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; | |||
//import com.jd.blockchain.utils.Transactional; | |||
// | |||
//public class GenericAccountSet<H extends AccountHeader, T extends GenericAccount<H>> implements AccountQuery<H, T>, Transactional { | |||
// | |||
// private Class<H> headerType; | |||
// | |||
// private MerkleAccountSet merkleAccountSet; | |||
// | |||
// public GenericAccountSet(Class<H> headerType, CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | |||
// VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
// this(headerType, null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); | |||
// } | |||
// | |||
// public GenericAccountSet(Class<H> headerType, HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
// ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
// AccountAccessPolicy accessPolicy) { | |||
// this.headerType = headerType; | |||
// this.merkleAccountSet = new MerkleAccountSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, accessPolicy); | |||
// } | |||
// | |||
// @Override | |||
// public MerkleProof getProof(Bytes address) { | |||
// return merkleAccountSet.getProof(address); | |||
// } | |||
// | |||
// @Override | |||
// public HashDigest getRootHash() { | |||
// return merkleAccountSet.getRootHash(); | |||
// } | |||
// | |||
// @Override | |||
// public boolean isUpdated() { | |||
// return merkleAccountSet.isUpdated(); | |||
// } | |||
// | |||
// @Override | |||
// public void commit() { | |||
// merkleAccountSet.commit(); | |||
// } | |||
// | |||
// @Override | |||
// public void cancel() { | |||
// merkleAccountSet.cancel(); | |||
// } | |||
// | |||
// @Override | |||
// public H[] getHeaders(int fromIndex, int count) { | |||
// merkleAccountSet.getHeaders(fromIndex, count) | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public long getTotal() { | |||
// // TODO Auto-generated method stub | |||
// return 0; | |||
// } | |||
// | |||
// @Override | |||
// public boolean contains(Bytes address) { | |||
// // TODO Auto-generated method stub | |||
// return false; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(String address) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(Bytes address) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(Bytes address, long version) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// | |||
//} |
@@ -0,0 +1,42 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.HashProof; | |||
/** | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class HashDegistList implements HashProof { | |||
private List<HashDigest> proofs = new ArrayList<HashDigest>(); | |||
public HashDegistList() { | |||
} | |||
public HashDegistList(HashProof proof) { | |||
concat(proof); | |||
} | |||
public void concat(HashProof proof) { | |||
int levels = proof.getLevels(); | |||
for (int i = levels; i > -1; i--) { | |||
proofs.add(proof.getHash(i)); | |||
} | |||
} | |||
@Override | |||
public int getLevels() { | |||
return proofs.size(); | |||
} | |||
@Override | |||
public HashDigest getHash(int level) { | |||
return proofs.get(level); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.HashProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface HashProvable { | |||
HashProof getProof(Bytes key); | |||
} |
@@ -5,11 +5,12 @@ import java.util.List; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
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.TypedKVEntry; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.TypedKVData; | |||
import com.jd.blockchain.ledger.KVDataVO; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
@@ -22,22 +23,25 @@ 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.ArrayUtils; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.DataIterator; | |||
import com.jd.blockchain.utils.QueryUtil; | |||
public class LedgerQueryService implements BlockchainQueryService { | |||
private static final KVDataEntry[] EMPTY_ENTRIES = new KVDataEntry[0]; | |||
private static final TypedKVEntry[] EMPTY_ENTRIES = new TypedKVEntry[0]; | |||
private HashDigest[] ledgerHashs; | |||
private LedgerQuery ledger; | |||
public LedgerQueryService(LedgerQuery ledger) { | |||
this.ledger = ledger; | |||
this.ledgerHashs = new HashDigest[] {ledger.getHash()}; | |||
this.ledgerHashs = new HashDigest[] { ledger.getHash() }; | |||
} | |||
private void checkLedgerHash(HashDigest ledgerHash) { | |||
if (!ledgerHashs[0].equals(ledgerHash)) { | |||
throw new LedgerException("Unsupport cross chain query!"); | |||
@@ -58,7 +62,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); | |||
return ledgerInfo; | |||
} | |||
@Override | |||
public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||
checkLedgerHash(ledgerHash); | |||
@@ -270,15 +274,15 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
@Override | |||
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | |||
public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { | |||
checkLedgerHash(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
return dataAccountSet.getAccount(Bytes.fromBase58(address)).getID(); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
if (keys == null || keys.length == 0) { | |||
return EMPTY_ENTRIES; | |||
} | |||
@@ -287,25 +291,26 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
long ver; | |||
for (int i = 0; i < entries.length; i++) { | |||
final String currKey = keys[i]; | |||
ver = dataAccount == null ? -1 : dataAccount.getDataVersion(Bytes.fromString(currKey)); | |||
ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); | |||
if (ver < 0) { | |||
entries[i] = new KVDataObject(currKey, -1, null); | |||
entries[i] = new TypedKVData(currKey, -1, null); | |||
} else { | |||
BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); | |||
entries[i] = new KVDataObject(currKey, ver, value); | |||
BytesValue value = dataAccount.getDataset().getValue(currKey, ver); | |||
entries[i] = new TypedKVData(currKey, ver, value); | |||
} | |||
} | |||
return entries; | |||
} | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
// parse kvInfoVO; | |||
List<String> keyList = new ArrayList<>(); | |||
List<Long> versionList = new ArrayList<>(); | |||
@@ -335,22 +340,22 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
long ver = -1; | |||
for (int i = 0; i < entries.length; i++) { | |||
// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
// dataAccount.getBytes(Bytes.fromString(keys[i]),1); | |||
ver = versions[i]; | |||
if (ver < 0) { | |||
entries[i] = new KVDataObject(keys[i], -1, null); | |||
entries[i] = new TypedKVData(keys[i], -1, null); | |||
} else { | |||
if (dataAccount.getDataEntriesTotalCount() == 0 | |||
|| dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null) { | |||
if (dataAccount.getDataset().getDataCount() == 0 | |||
|| dataAccount.getDataset().getValue(keys[i], ver) == null) { | |||
// is the address is not exist; the result is null; | |||
entries[i] = new KVDataObject(keys[i], -1, null); | |||
entries[i] = new TypedKVData(keys[i], -1, null); | |||
} else { | |||
BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); | |||
entries[i] = new KVDataObject(keys[i], ver, value); | |||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | |||
entries[i] = new TypedKVData(keys[i], ver, value); | |||
} | |||
} | |||
} | |||
@@ -359,14 +364,22 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
checkLedgerHash(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); | |||
return dataAccount.getDataEntries(pages[0], pages[1]); | |||
// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); | |||
// return dataAccount.getDataset().getDataEntry(key, version).getDataEntries(pages[0], pages[1]); | |||
DataIterator<String, TypedValue> iterator = dataAccount.getDataset().iterator(); | |||
iterator.skip(fromIndex); | |||
DataEntry<String, TypedValue>[] dataEntries = iterator.next(count); | |||
TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, | |||
e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); | |||
return typedKVEntries; | |||
} | |||
@Override | |||
@@ -376,7 +389,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
return dataAccount.getDataEntriesTotalCount(); | |||
return dataAccount.getDataset().getDataCount(); | |||
} | |||
@Override | |||
@@ -388,7 +401,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
@Override | |||
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
checkLedgerHash(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
@@ -397,7 +410,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
@Override | |||
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
checkLedgerHash(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
@@ -406,7 +419,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||
} | |||
@Override | |||
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
checkLedgerHash(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
@@ -3,15 +3,21 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
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.HashProof; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
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.Dataset; | |||
import com.jd.blockchain.utils.DatasetHelper; | |||
import com.jd.blockchain.utils.DatasetHelper.DataChangedListener; | |||
import com.jd.blockchain.utils.DatasetHelper.TypeMapper; | |||
import com.jd.blockchain.utils.Transactional; | |||
/** | |||
@@ -20,94 +26,166 @@ import com.jd.blockchain.utils.Transactional; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class MerkleAccount implements AccountHeader, MerkleProvable, Transactional { | |||
public class MerkleAccount implements CompositeAccount, HashProvable, MerkleSnapshot, Transactional { | |||
private BlockchainIdentity bcid; | |||
private static final Bytes HEADER_PREFIX = Bytes.fromString("HD/"); | |||
private static final Bytes DATA_PREFIX = Bytes.fromString("DT/"); | |||
protected MerkleDataSet dataset; | |||
private static final Bytes KEY_HEADER_ROOT = Bytes.fromString("HEADER"); | |||
private static final Bytes KEY_DATA_ROOT = Bytes.fromString("DATA"); | |||
private static final String KEY_PUBKEY = "PUBKEY"; | |||
private BlockchainIdentity accountID; | |||
private MerkleDataSet rootDataset; | |||
private MerkleDataSet headerDataset; | |||
private MerkleDataSet dataDataset; | |||
private Dataset<String, TypedValue> typedHeader; | |||
private Dataset<String, TypedValue> typedData; | |||
// private long version; | |||
/** | |||
* Create a new Account with the specified address and pubkey; <br> | |||
* Create a new Account with the specified identity(address and pubkey); <br> | |||
* | |||
* At the same time, a empty merkle dataset is also created for this account, | |||
* which is used for storing data of this account.<br> | |||
* | |||
* Note that, the blockchain identity of the account is not stored in the | |||
* account's merkle dataset, but is stored by the outer invoker; | |||
* | |||
* @param address | |||
* @param pubKey | |||
* This new account will be writable. <br> | |||
* | |||
* @param accountID Identity of this new account; | |||
* @param cryptoSetting Settings about crypto operations; | |||
* @param keyPrefix Prefix of all keys in this account's dataset; | |||
* @param exStorage The base storage for existance operation; | |||
* @param verStorage The base storage for versioning operation; | |||
*/ | |||
public MerkleAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix, | |||
public MerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { | |||
this(address, pubKey, null, cryptoSetting, keyPrefix, exStorage, verStorage, false); | |||
// 初始化数据集; | |||
initializeDatasets(null, cryptoSetting, keyPrefix, exStorage, verStorage, false); | |||
initPubKey(accountID.getPubKey()); | |||
this.accountID = accountID; | |||
} | |||
/** | |||
* Create a new Account with the specified address and pubkey; <br> | |||
* Create a account instance with the specified address and root hash; load it's | |||
* merkle dataset from the specified root hash. This merkle dateset is used for | |||
* storing data of this account.<br> | |||
* | |||
* At the same time, a empty merkle dataset is also created for this account, | |||
* which is used for storing data of this account.<br> | |||
* | |||
* Note that, the blockchain identity of the account is not stored in the | |||
* account's merkle dataset, but is stored by the outer invoker; | |||
* | |||
* @param bcid | |||
* @param cryptoSetting | |||
* @param exStorage | |||
* @param verStorage | |||
* @param accessPolicy | |||
* @param address Address of this account; | |||
* @param rootHash Merkle root hash of this account; It can not be null; | |||
* @param cryptoSetting Settings about crypto operations; | |||
* @param keyPrefix Prefix of all keys in this account's dataset; | |||
* @param exStorage The base storage for existance operation; | |||
* @param verStorage The base storage for versioning operation; | |||
* @param readonly Readonly about this account's dataset; | |||
*/ | |||
public MerkleAccount(BlockchainIdentity bcid, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { | |||
this(bcid, null, cryptoSetting, keyPrefix, exStorage, verStorage, false); | |||
public MerkleAccount(Bytes address, HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
if (rootHash == null) { | |||
throw new IllegalArgumentException("Specified a null root hash for account[" + address.toBase58() + "]!"); | |||
} | |||
// 初始化数据集; | |||
initializeDatasets(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
// 初始化账户的身份; | |||
PubKey pubKey = loadPubKey(); | |||
this.accountID = new AccountID(address, pubKey); | |||
} | |||
/** | |||
* Create a account instance with the specified address and pubkey and load it's | |||
* 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 set to a null value, | |||
* an empty merkle dataset is created; | |||
* @param cryptoSetting | |||
* @param exStorage | |||
* @param verStorage | |||
* @param readonly | |||
* @param accessPolicy | |||
*/ | |||
public MerkleAccount(Bytes address, PubKey pubKey, HashDigest dataRootHash, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
this(new BlockchainIdentityData(address, pubKey), dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, | |||
private void initializeDatasets(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
// 加载“根数据集” | |||
this.rootDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
// 初始化数据修改监听器; | |||
DataChangedListener<String, TypedValue> dataChangedListener = new DataChangedListener<String, TypedValue>() { | |||
@Override | |||
public void onChanged(String key, TypedValue value, long expectedVersion, long newVersion) { | |||
onUpdated(key, value, expectedVersion, newVersion); | |||
} | |||
}; | |||
TypeMapper<byte[], TypedValue> valueMapper = new TypeMapper<byte[], TypedValue>() { | |||
@Override | |||
public byte[] encode(TypedValue t2) { | |||
return BinaryProtocol.encode(t2, BytesValue.class); | |||
} | |||
@Override | |||
public TypedValue decode(byte[] t1) { | |||
BytesValue v = BinaryProtocol.decodeAs(t1, BytesValue.class); | |||
return TypedValue.wrap(v); | |||
} | |||
}; | |||
// 加载“头数据集”; | |||
HashDigest headerRoot = loadHeaderRoot(); | |||
Bytes headerPrefix = keyPrefix.concat(HEADER_PREFIX); | |||
this.headerDataset = new MerkleDataSet(headerRoot, cryptoSetting, headerPrefix, exStorage, verStorage, | |||
readonly); | |||
this.typedHeader = DatasetHelper.listen(DatasetHelper.map(headerDataset, valueMapper), dataChangedListener); | |||
// 加载“主数据集” | |||
HashDigest dataRoot = loadDataRoot(); | |||
Bytes dataPrefix = keyPrefix.concat(DATA_PREFIX); | |||
this.dataDataset = new MerkleDataSet(dataRoot, cryptoSetting, dataPrefix, exStorage, verStorage, readonly); | |||
this.typedData = DatasetHelper.listen(DatasetHelper.map(dataDataset, valueMapper), dataChangedListener); | |||
} | |||
public MerkleAccount(BlockchainIdentity bcid, HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
this.bcid = bcid; | |||
this.dataset = new MerkleDataSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
private HashDigest loadHeaderRoot() { | |||
byte[] hashBytes = rootDataset.getValue(KEY_HEADER_ROOT); | |||
if (hashBytes == null) { | |||
return null; | |||
} | |||
return new HashDigest(hashBytes); | |||
} | |||
private HashDigest loadDataRoot() { | |||
byte[] hashBytes = rootDataset.getValue(KEY_DATA_ROOT); | |||
if (hashBytes == null) { | |||
return null; | |||
} | |||
return new HashDigest(hashBytes); | |||
} | |||
private long getHeaderRootVersion() { | |||
return rootDataset.getVersion(KEY_HEADER_ROOT); | |||
} | |||
private long getDataRootVersion() { | |||
return rootDataset.getVersion(KEY_DATA_ROOT); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.AccountDataSet#getAddress() | |||
*/ | |||
@Override | |||
public Bytes getAddress() { | |||
return bcid.getAddress(); | |||
return accountID.getAddress(); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.AccountDataSet#getPubKey() | |||
*/ | |||
@Override | |||
public PubKey getPubKey() { | |||
return bcid.getPubKey(); | |||
return accountID.getPubKey(); | |||
} | |||
@Override | |||
public BlockchainIdentity getID() { | |||
return accountID; | |||
} | |||
public Dataset<String, TypedValue> getHeaders() { | |||
return typedHeader; | |||
} | |||
@Override | |||
public Dataset<String, TypedValue> getDataset() { | |||
return typedData; | |||
} | |||
/* | |||
@@ -117,12 +195,22 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction | |||
*/ | |||
@Override | |||
public HashDigest getRootHash() { | |||
return dataset.getRootHash(); | |||
return rootDataset.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return dataset.getProof(key); | |||
public HashProof getProof(Bytes key) { | |||
MerkleProof dataProof = dataDataset.getProof(key); | |||
if (dataProof == null) { | |||
return null; | |||
} | |||
MerkleProof rootProof = rootDataset.getProof(KEY_DATA_ROOT); | |||
if (rootProof == null) { | |||
return null; | |||
} | |||
HashDegistList proof = new HashDegistList(rootProof); | |||
proof.concat(dataProof); | |||
return proof; | |||
} | |||
/** | |||
@@ -131,90 +219,298 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction | |||
* @return | |||
*/ | |||
public boolean isReadonly() { | |||
return dataset.isReadonly(); | |||
return dataDataset.isReadonly() || headerDataset.isReadonly(); | |||
} | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
* | |||
* The value of the key will be updated only if it's latest version equals the | |||
* specified version argument. <br> | |||
* If the key doesn't exist, the version checking will be ignored, and key will | |||
* be created with a new sequence number as id. <br> | |||
* It also could specify the version argument to -1 to ignore the version | |||
* checking. | |||
* <p> | |||
* 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 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> | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
* @param pubKey | |||
*/ | |||
public long setBytes(Bytes key, BytesValue value, long version) { | |||
byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); | |||
return dataset.setValue(key, bytesValue, version); | |||
private void initPubKey(PubKey pubKey) { | |||
long v = typedHeader.setValue(KEY_PUBKEY, TypedValue.fromPubKey(pubKey), -1); | |||
if (v < 0) { | |||
throw new LedgerException("PubKey storage conflict!"); | |||
} | |||
} | |||
/** | |||
* Return the latest version entry associated the specified key; If the key | |||
* doesn't exist, then return -1; | |||
* 加载公钥; | |||
* | |||
* @param key | |||
* @return | |||
*/ | |||
public long getVersion(Bytes key) { | |||
return dataset.getVersion(key); | |||
private PubKey loadPubKey() { | |||
TypedValue value = typedHeader.getValue(KEY_PUBKEY); | |||
if (value == null) { | |||
return null; | |||
} | |||
return value.pubKeyValue(); | |||
} | |||
/** | |||
* return the latest version's value; | |||
* 当写入新值时触发此方法; | |||
* | |||
* @param key | |||
* @return return null if not exist; | |||
* @param value | |||
* @param newVersion | |||
*/ | |||
public BytesValue getBytes(Bytes key) { | |||
byte[] bytesValue = dataset.getValue(key); | |||
if (bytesValue == null) { | |||
return null; | |||
} | |||
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { | |||
} | |||
/** | |||
* Return the specified version's value; | |||
* 当账户数据提交后触发此方法;<br> | |||
* | |||
* @param key | |||
* @param version | |||
* @return return null if not exist; | |||
* 此方法默认会返回新的账户版本号,等于当前版本号加 1 ; | |||
* | |||
* @param previousRootHash 提交前的根哈希;如果是新账户的首次提交,则为 null; | |||
* @param newRootHash 新的根哈希; | |||
*/ | |||
public BytesValue getBytes(Bytes key, long version) { | |||
byte[] bytesValue = dataset.getValue(key, version); | |||
if (bytesValue == null) { | |||
return null; | |||
} | |||
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return dataset.isUpdated(); | |||
return headerDataset.isUpdated() || dataDataset.isUpdated() || rootDataset.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
dataset.commit(); | |||
if (headerDataset.isUpdated()) { | |||
headerDataset.commit(); | |||
long version = getHeaderRootVersion(); | |||
rootDataset.setValue(KEY_HEADER_ROOT, headerDataset.getRootHash().toBytes(), version); | |||
} | |||
if (dataDataset.isUpdated()) { | |||
long version = getDataRootVersion(); | |||
dataDataset.commit(); | |||
rootDataset.setValue(KEY_DATA_ROOT, dataDataset.getRootHash().toBytes(), version); | |||
} | |||
if (rootDataset.isUpdated()) { | |||
HashDigest previousRootHash = rootDataset.getRootHash(); | |||
rootDataset.commit(); | |||
onCommited(previousRootHash, rootDataset.getRootHash()); | |||
} | |||
} | |||
@Override | |||
public void cancel() { | |||
dataset.cancel(); | |||
headerDataset.cancel(); | |||
dataDataset.cancel(); | |||
rootDataset.cancel(); | |||
} | |||
// ---------------------- | |||
private class AccountID implements BlockchainIdentity { | |||
private Bytes address; | |||
private PubKey pubKey; | |||
public AccountID(Bytes address, PubKey pubKey) { | |||
this.address = address; | |||
this.pubKey = pubKey; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
} | |||
// private static class MerkleDatasetAdapter implements Dataset<String, BytesValue> { | |||
// | |||
// private static DataChangedListener NULL_LISTENER = new DataChangedListener() { | |||
// @Override | |||
// public void onChanged(Bytes key, BytesValue value, long newVersion) { | |||
// } | |||
// }; | |||
// | |||
// private DataChangedListener changedListener; | |||
// | |||
// private MerkleDataSet dataset; | |||
// | |||
// public MerkleDataSet getDataset() { | |||
// return dataset; | |||
// } | |||
// | |||
// @SuppressWarnings("unused") | |||
// public MerkleDatasetAdapter(MerkleDataSet dataset) { | |||
// this(dataset, NULL_LISTENER); | |||
// } | |||
// | |||
// public MerkleDatasetAdapter(MerkleDataSet dataset, DataChangedListener listener) { | |||
// this.dataset = dataset; | |||
// this.changedListener = listener == null ? NULL_LISTENER : listener; | |||
// } | |||
// | |||
// @Override | |||
// public DataEntry<String, BytesValue> getDataEntry(String key) { | |||
// return new VersioningKVEntryWraper(dataset.getDataEntry(Bytes.fromString(key))); | |||
// } | |||
// | |||
// @Override | |||
// public DataEntry<String, BytesValue> getDataEntry(String key, long version) { | |||
// return new VersioningKVEntryWraper(dataset.getDataEntry(Bytes.fromString(key), version)); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * 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 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> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// @Override | |||
// public long setValue(Bytes key, BytesValue value, long version) { | |||
// byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); | |||
// long v = dataset.setValue(key, bytesValue, version); | |||
// if (v > -1) { | |||
// changedListener.onChanged(key, value, v); | |||
// } | |||
// return v; | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// @Override | |||
// public long getVersion(Bytes key) { | |||
// return dataset.getVersion(key); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// @Override | |||
// public BytesValue getValue(Bytes key) { | |||
// byte[] bytesValue = dataset.getValue(key); | |||
// if (bytesValue == null) { | |||
// return null; | |||
// } | |||
// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
// } | |||
// | |||
// /** | |||
// * Return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// @Override | |||
// public BytesValue getValue(Bytes key, long version) { | |||
// byte[] bytesValue = dataset.getValue(key, version); | |||
// if (bytesValue == null) { | |||
// return null; | |||
// } | |||
// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
// } | |||
// | |||
// @Override | |||
// public long getDataCount() { | |||
// return dataset.getDataCount(); | |||
// } | |||
// | |||
// @Override | |||
// public long setValue(String key, BytesValue value, long version) { | |||
// byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class); | |||
// return dataset.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// @Override | |||
// public BytesValue getValue(String key, long version) { | |||
// byte[] bytesValue = dataset.getValue(key, version); | |||
// if (bytesValue == null) { | |||
// return null; | |||
// } | |||
// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
// } | |||
// | |||
// @Override | |||
// public BytesValue getValue(String key) { | |||
// byte[] bytesValue = dataset.getValue(key); | |||
// if (bytesValue == null) { | |||
// return null; | |||
// } | |||
// return BinaryProtocol.decodeAs(bytesValue, BytesValue.class); | |||
// } | |||
// | |||
// @Override | |||
// public long getVersion(String key) { | |||
// return dataset.getVersion(key); | |||
// } | |||
// | |||
// @Override | |||
// public DataEntry<String, BytesValue> getDataEntry(String key) { | |||
// return new VersioningKVEntryWraper<String>(dataset.getDataEntry(key)); | |||
// } | |||
// | |||
// @Override | |||
// public DataEntry<String, BytesValue> getDataEntry(String key, long version) { | |||
// return new VersioningKVEntryWraper<String>(dataset.getDataEntry(key, version)); | |||
// } | |||
// } | |||
// private static interface DataChangedListener { | |||
// | |||
// void onChanged(Bytes key, BytesValue value, long newVersion); | |||
// | |||
// } | |||
// private static class VersioningKVEntryWraper implements DataEntry<String, BytesValue> { | |||
// | |||
// private DataEntry<Bytes, byte[]> kv; | |||
// | |||
// public VersioningKVEntryWraper(DataEntry<Bytes, byte[]> kv) { | |||
// this.kv = kv; | |||
// } | |||
// | |||
// @Override | |||
// public String getKey() { | |||
// return kv.getKey().toUTF8String(); | |||
// } | |||
// | |||
// @Override | |||
// public long getVersion() { | |||
// return kv.getVersion(); | |||
// } | |||
// | |||
// @Override | |||
// public BytesValue getValue() { | |||
// return BinaryProtocol.decodeAs(kv.getValue(), BytesValue.class); | |||
// } | |||
// | |||
// } | |||
} |
@@ -0,0 +1,12 @@ | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//import com.jd.blockchain.binaryproto.DataField; | |||
//import com.jd.blockchain.ledger.BlockchainIdentity; | |||
//import com.jd.blockchain.ledger.MerkleSnapshot; | |||
// | |||
//public interface MerkleAccountHeader extends MerkleSnapshot { | |||
// | |||
// @DataField(order = 1, refContract = true) | |||
// BlockchainIdentity getID(); | |||
// | |||
//} |
@@ -3,31 +3,35 @@ package com.jd.blockchain.ledger.core; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
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.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
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.DataEntry; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<MerkleAccount> { | |||
public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<CompositeAccount> { | |||
static { | |||
DataContractRegistry.register(MerkleSnapshot.class); | |||
DataContractRegistry.register(AccountHeader.class); | |||
DataContractRegistry.register(BlockchainIdentity.class); | |||
} | |||
private final String keyPrefix; | |||
private final Bytes keyPrefix; | |||
/** | |||
* 账户根哈希的数据集; | |||
*/ | |||
private MerkleDataSet merkleDataset; | |||
/** | |||
@@ -36,7 +40,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
* | |||
*/ | |||
// TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; | |||
private Map<Bytes, InnerVersioningAccount> latestAccountsCache = new HashMap<>(); | |||
private Map<Bytes, InnerMerkleAccount> latestAccountsCache = new HashMap<>(); | |||
private ExPolicyKVStorage baseExStorage; | |||
@@ -44,7 +48,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
private CryptoSetting cryptoSetting; | |||
private boolean updated; | |||
private volatile boolean updated; | |||
private AccountAccessPolicy accessPolicy; | |||
@@ -56,12 +60,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
merkleDataset.setReadonly(); | |||
} | |||
public MerkleAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | |||
public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); | |||
} | |||
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
this.keyPrefix = keyPrefix; | |||
@@ -70,6 +74,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
this.baseVerStorage = verStorage; | |||
this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, | |||
this.baseVerStorage, readonly); | |||
this.accessPolicy = accessPolicy; | |||
} | |||
@@ -83,29 +88,17 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
return merkleDataset.getProof(key); | |||
} | |||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||
byte[][] results = merkleDataset.getLatestValues(fromIndex, count); | |||
AccountHeader[] accounts = new AccountHeader[results.length]; | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
DataEntry<Bytes, byte[]>[] results = merkleDataset.getLatestDataEntries(fromIndex, count); | |||
BlockchainIdentity[] ids = new BlockchainIdentity[results.length]; | |||
for (int i = 0; i < results.length; i++) { | |||
accounts[i] = deserialize(results[i]); | |||
InnerMerkleAccount account = createAccount(results[i].getKey(), new HashDigest(results[i].getValue()), | |||
results[i].getVersion(), true); | |||
ids[i] = account.getID(); | |||
} | |||
return accounts; | |||
} | |||
// private VersioningAccount deserialize(byte[] txBytes) { | |||
//// return BinaryEncodingUtils.decode(txBytes, null, Account.class); | |||
// AccountHeaderData accInfo = BinaryEncodingUtils.decode(txBytes); | |||
//// return new BaseAccount(accInfo.getAddress(), accInfo.getPubKey(), null, | |||
// cryptoSetting, | |||
//// baseExStorage, baseVerStorage, true, accessPolicy); | |||
// return new VersioningAccount(accInfo.getAddress(), accInfo.getPubKey(), | |||
// accInfo.getRootHash(), cryptoSetting, | |||
// keyPrefix, baseExStorage, baseVerStorage, true, accessPolicy, accInfo.); | |||
// } | |||
private AccountHeader deserialize(byte[] txBytes) { | |||
return BinaryProtocol.decode(txBytes); | |||
return ids; | |||
} | |||
/** | |||
@@ -118,7 +111,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
} | |||
@Override | |||
public MerkleAccount getAccount(String address) { | |||
public CompositeAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
@@ -128,7 +121,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
* @param address | |||
* @return | |||
*/ | |||
public MerkleAccount getAccount(Bytes address) { | |||
@Override | |||
public CompositeAccount getAccount(Bytes address) { | |||
return this.getAccount(address, -1); | |||
} | |||
@@ -142,25 +136,30 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
* @return | |||
*/ | |||
public boolean contains(Bytes address) { | |||
long latestVersion = getVersion(address); | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 无论是新注册未提交的,还是缓存已提交的账户实例,都认为是存在; | |||
return true; | |||
} | |||
long latestVersion = merkleDataset.getVersion(address); | |||
return latestVersion > -1; | |||
} | |||
/** | |||
* 返回指定账户的版本; <br> | |||
* 如果账户已经注册,则返回该账户的最新版本,值大于等于 0; <br> | |||
* 如果账户不存在,则返回 -1; <br> | |||
* 如果指定的账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 | |||
* {@link #commit()} 方法),此方法对该账户仍然返回 0; | |||
* 如果账户不存在,则返回 -1;<br> | |||
* 如果账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 {@link #commit()} | |||
* 方法),则返回 -1; <br> | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
public long getVersion(Bytes address) { | |||
InnerVersioningAccount acc = latestAccountsCache.get(address); | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 已注册尚未提交,也返回 -1; | |||
return acc.version == -1 ? 0 : acc.version; | |||
return acc.getVersion(); | |||
} | |||
return merkleDataset.getVersion(address); | |||
@@ -175,12 +174,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
* @param version 账户版本;如果指定为 -1,则返回最新版本; | |||
* @return | |||
*/ | |||
public MerkleAccount getAccount(Bytes address, long version) { | |||
public CompositeAccount getAccount(Bytes address, long version) { | |||
version = version < 0 ? -1 : version; | |||
InnerVersioningAccount acc = latestAccountsCache.get(address); | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null && version == -1) { | |||
return acc; | |||
} else if (acc != null && acc.version == version) { | |||
} else if (acc != null && acc.getVersion() == version) { | |||
return acc; | |||
} | |||
@@ -194,7 +193,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
} | |||
// 如果是不存在的,或者刚刚新增未提交的账户,则前面一步查询到的 latestVersion 小于 0, 代码不会执行到此; | |||
if (acc != null && acc.version != latestVersion) { | |||
if (acc != null && acc.getVersion() != latestVersion) { | |||
// 当执行到此处时,并且缓冲列表中缓存了最新的版本, | |||
// 如果当前缓存的最新账户的版本和刚刚从存储中检索得到的最新版本不一致,可能存在外部的并发更新,这超出了系统设计的逻辑; | |||
@@ -205,21 +204,15 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
} | |||
// Now, be sure that "acc == null", so get account from storage; | |||
byte[] bytes = merkleDataset.getValue(address, version); | |||
if (bytes == null) { | |||
return null; | |||
} | |||
// Set readonly for the old version account; | |||
boolean readonly = (version > -1 && version < latestVersion) || isReadonly(); | |||
// String prefix = address.concat(LedgerConsts.KEY_SEPERATOR); | |||
// ExPolicyKVStorage ss = PrefixAppender.prefix(prefix, baseExStorage); | |||
// VersioningKVStorage vs = PrefixAppender.prefix(prefix, baseVerStorage); | |||
// BaseAccount accDS = deserialize(bytes, cryptoSetting, ss, vs, readonly); | |||
String prefix = keyPrefix + address; | |||
acc = deserialize(bytes, cryptoSetting, prefix, baseExStorage, baseVerStorage, readonly, latestVersion); | |||
long qVersion = version == -1 ? latestVersion : version; | |||
// load account from storage; | |||
acc = loadAccount(address, readonly, qVersion); | |||
if (acc == null) { | |||
return null; | |||
} | |||
if (!readonly) { | |||
// cache the latest version witch enable reading and writing; | |||
// readonly version of account not necessary to be cached; | |||
@@ -228,6 +221,10 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
return acc; | |||
} | |||
public CompositeAccount register(Bytes address, PubKey pubKey) { | |||
return register(new BlockchainIdentityData(address, pubKey)); | |||
} | |||
/** | |||
* 注册一个新账户; <br> | |||
* | |||
@@ -239,16 +236,18 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
* @param pubKey 公钥; | |||
* @return 注册成功的账户对象; | |||
*/ | |||
public MerkleAccount register(Bytes address, PubKey pubKey) { | |||
public CompositeAccount register(BlockchainIdentity accountId) { | |||
if (isReadonly()) { | |||
throw new IllegalArgumentException("This AccountSet is readonly!"); | |||
} | |||
Bytes address = accountId.getAddress(); | |||
PubKey pubKey = accountId.getPubKey(); | |||
verifyAddressEncoding(address, pubKey); | |||
InnerVersioningAccount cachedAcc = latestAccountsCache.get(address); | |||
InnerMerkleAccount cachedAcc = latestAccountsCache.get(address); | |||
if (cachedAcc != null) { | |||
if (cachedAcc.version < 0) { | |||
if (cachedAcc.getVersion() < 0) { | |||
// 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; | |||
return cachedAcc; | |||
} | |||
@@ -264,17 +263,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
throw new LedgerException("Account Registering was rejected for the access policy!"); | |||
} | |||
// String prefix = address.concat(LedgerConsts.KEY_SEPERATOR); | |||
// ExPolicyKVStorage accExStorage = PrefixAppender.prefix(prefix, | |||
// baseExStorage); | |||
// VersioningKVStorage accVerStorage = PrefixAppender.prefix(prefix, | |||
// baseVerStorage); | |||
// BaseAccount accDS = createInstance(address, pubKey, cryptoSetting, | |||
// accExStorage, accVerStorage); | |||
String prefix = keyPrefix + address; | |||
InnerVersioningAccount acc = createInstance(address, pubKey, cryptoSetting, prefix, baseExStorage, baseVerStorage, | |||
-1); | |||
Bytes prefix = keyPrefix.concat(address); | |||
InnerMerkleAccount acc = createInstance(accountId, cryptoSetting, prefix); | |||
latestAccountsCache.put(address, acc); | |||
updated = true; | |||
@@ -288,20 +278,50 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
} | |||
} | |||
private InnerVersioningAccount createInstance(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) { | |||
return new InnerVersioningAccount(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage, version); | |||
private InnerMerkleAccount createInstance(BlockchainIdentity header, CryptoSetting cryptoSetting, Bytes keyPrefix) { | |||
return new InnerMerkleAccount(header, cryptoSetting, keyPrefix, baseExStorage, baseVerStorage); | |||
} | |||
/** | |||
* 加载指定版本的账户; | |||
* | |||
* @param address 账户地址; | |||
* @param readonly 是否只读; | |||
* @param version 账户的版本;大于等于 0 ; | |||
* @return | |||
*/ | |||
private InnerMerkleAccount loadAccount(Bytes address, boolean readonly, long version) { | |||
byte[] rootHashBytes = merkleDataset.getValue(address, version); | |||
if (rootHashBytes == null) { | |||
return null; | |||
} | |||
HashDigest rootHash = new HashDigest(rootHashBytes); | |||
return createAccount(address, rootHash, version, readonly); | |||
} | |||
private InnerVersioningAccount deserialize(byte[] bytes, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, long version) { | |||
AccountHeader accInfo = BinaryProtocol.decode(bytes); | |||
return new InnerVersioningAccount(accInfo.getAddress(), accInfo.getPubKey(), accInfo.getRootHash(), cryptoSetting, | |||
keyPrefix, exStorage, verStorage, readonly, version); | |||
private InnerMerkleAccount createAccount(Bytes address, HashDigest rootHash, long version, boolean readonly) { | |||
// prefix; | |||
Bytes prefix = keyPrefix.concat(address); | |||
return new InnerMerkleAccount(address, version, rootHash, cryptoSetting, prefix, baseExStorage, baseVerStorage, | |||
readonly); | |||
} | |||
private byte[] serialize(AccountHeader account) { | |||
return BinaryProtocol.encode(account, AccountHeader.class); | |||
// TODO:优化:区块链身份(地址+公钥)与其Merkle树根哈希分开独立存储; | |||
// 不必作为一个整块,避免状态数据写入时频繁重写公钥,尤其某些算法的公钥可能很大; | |||
/** | |||
* 保存账户的根哈希,返回账户的新版本; | |||
* | |||
* @param account | |||
* @return | |||
*/ | |||
private long saveAccount(InnerMerkleAccount account) { | |||
// 提交更改,更新哈希; | |||
account.commit(); | |||
return account.getVersion(); | |||
} | |||
@Override | |||
@@ -315,17 +335,10 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
return; | |||
} | |||
try { | |||
for (InnerVersioningAccount acc : latestAccountsCache.values()) { | |||
for (InnerMerkleAccount acc : latestAccountsCache.values()) { | |||
// updated or new created; | |||
if (acc.isUpdated() || acc.version < 0) { | |||
// 提交更改,更新哈希; | |||
acc.commit(); | |||
byte[] value = serialize(acc); | |||
long ver = merkleDataset.setValue(acc.getAddress(), value, acc.version); | |||
if (ver < 0) { | |||
// Update fail; | |||
throw new LedgerException("Account updating fail! --[Address=" + acc.getAddress() + "]"); | |||
} | |||
if (acc.isUpdated() || acc.getVersion() < 0) { | |||
saveAccount(acc); | |||
} | |||
} | |||
merkleDataset.commit(); | |||
@@ -343,7 +356,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
Bytes[] addresses = new Bytes[latestAccountsCache.size()]; | |||
latestAccountsCache.keySet().toArray(addresses); | |||
for (Bytes address : addresses) { | |||
InnerVersioningAccount acc = latestAccountsCache.remove(address); | |||
InnerMerkleAccount acc = latestAccountsCache.remove(address); | |||
// cancel; | |||
if (acc.isUpdated()) { | |||
acc.cancel(); | |||
@@ -352,107 +365,46 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||
updated = false; | |||
} | |||
public static class AccountHeaderData implements AccountHeader { | |||
private Bytes address; | |||
private PubKey pubKey; | |||
private HashDigest rootHash; | |||
public AccountHeaderData(Bytes address, PubKey pubKey, HashDigest rootHash) { | |||
this.address = address; | |||
this.pubKey = pubKey; | |||
this.rootHash = rootHash; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
/** | |||
* 内部实现的账户,监听和同步账户数据的变更; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private class InnerMerkleAccount extends MerkleAccount { | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
private long version; | |||
@Override | |||
public HashDigest getRootHash() { | |||
return rootHash; | |||
public InnerMerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { | |||
super(accountID, cryptoSetting, keyPrefix, exStorage, verStorage); | |||
this.version = -1; | |||
} | |||
} | |||
private class InnerVersioningAccount extends MerkleAccount { | |||
// private final BaseAccount account; | |||
private final long version; | |||
// public VersioningAccount(BaseAccount account, long version) { | |||
// this.account = account; | |||
// this.version = version; | |||
// } | |||
public InnerVersioningAccount(Bytes address, PubKey pubKey, HashDigest rootHash, CryptoSetting cryptoSetting, | |||
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
long version) { | |||
super(address, pubKey, rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
public InnerMerkleAccount(Bytes address, long version, HashDigest dataRootHash, CryptoSetting cryptoSetting, | |||
Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
super(address, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
this.version = version; | |||
} | |||
public InnerVersioningAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) { | |||
super(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage); | |||
this.version = version; | |||
@Override | |||
protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { | |||
updated = true; | |||
} | |||
// @Override | |||
// public Bytes getAddress() { | |||
// return account.getAddress(); | |||
// } | |||
// | |||
// @Override | |||
// public PubKey getPubKey() { | |||
// return account.getPubKey(); | |||
// } | |||
// | |||
// @Override | |||
// public HashDigest getRootHash() { | |||
// return account.getRootHash(); | |||
// } | |||
// | |||
// @Override | |||
// public MerkleProof getProof(Bytes key) { | |||
// return account.getProof(key); | |||
// } | |||
// | |||
// @Override | |||
// public boolean isReadonly() { | |||
// return account.isReadonly(); | |||
// } | |||
@Override | |||
public long setBytes(Bytes key, BytesValue value, long version) { | |||
long v = super.setBytes(key, value, version); | |||
if (v > -1) { | |||
updated = true; | |||
protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { | |||
long newVersion = merkleDataset.setValue(this.getAddress(), newRootHash.toBytes(), version); | |||
if (newVersion < 0) { | |||
// Update fail; | |||
throw new LedgerException("Account updating fail! --[Address=" + this.getAddress() + "]"); | |||
} | |||
return v; | |||
this.version = newVersion; | |||
} | |||
// @Override | |||
// public long getKeyVersion(Bytes key) { | |||
// return account.getKeyVersion(key); | |||
// } | |||
// | |||
// @Override | |||
// public byte[] getBytes(Bytes key) { | |||
// return account.getBytes(key); | |||
// } | |||
// | |||
// @Override | |||
// public byte[] getBytes(Bytes key, long version) { | |||
// return account.getBytes(key, version); | |||
// } | |||
public long getVersion() { | |||
return version; | |||
} | |||
} | |||
@@ -0,0 +1,74 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.Map; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
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 MerkleDataCluster implements Transactional, MerkleSnapshot { | |||
private boolean readonly; | |||
private MerkleDataSet rootDS; | |||
private Map<Bytes, MerkleDataSet> partitions; | |||
/** | |||
* Create an empty readable {@link MerkleDataCluster} instance; | |||
*/ | |||
public MerkleDataCluster(CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
this(null, setting, keyPrefix, exPolicyStorage, versioningStorage, false); | |||
} | |||
/** | |||
* Create an {@link MerkleDataCluster} instance; | |||
* | |||
* @param rootHash root hash of this {@link MerkleDataCluster} instance; | |||
* @param readonly whether read only; | |||
*/ | |||
public MerkleDataCluster(HashDigest rootHash, CryptoSetting setting, Bytes keyPrefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
this.rootDS = new MerkleDataSet(rootHash, setting, keyPrefix, exPolicyStorage, versioningStorage, readonly); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return rootDS.getRootHash(); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return rootDS.isUpdated(); | |||
} | |||
// public VersioningMap<Bytes, byte[]> getPartition(Bytes name) { | |||
// return getPartition(name, false); | |||
// } | |||
// | |||
// public VersioningMap<Bytes, byte[]> getPartition(Bytes name, boolean create) { | |||
// | |||
// } | |||
// | |||
// public VersioningMap<Bytes, byte[]> createPartition(Bytes name) { | |||
// | |||
// } | |||
@Override | |||
public void commit() { | |||
// TODO Auto-generated method stub | |||
} | |||
@Override | |||
public void cancel() { | |||
// TODO Auto-generated method stub | |||
} | |||
} |
@@ -1,11 +1,12 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
public interface MerkleDataEntry { | |||
VersioningKVEntry getData(); | |||
DataEntry<Bytes, byte[]> getData(); | |||
MerkleProof getProof(); | |||
} |
@@ -7,11 +7,14 @@ 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.ArrayUtils; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.DataIterator; | |||
import com.jd.blockchain.utils.Dataset; | |||
import com.jd.blockchain.utils.Transactional; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
@@ -23,23 +26,24 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class MerkleDataSet implements Transactional, MerkleProvable { | |||
public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Bytes, byte[]> { | |||
/** | |||
* 4 MB MaxSize of value; | |||
*/ | |||
public static final int MAX_SIZE_OF_VALUE = 4 * 1024 * 1024; | |||
public static final String ORIG_KEY_SEPERATOR = LedgerConsts.KEY_SEPERATOR; | |||
public static final String SN_PREFIX = "SN" + ORIG_KEY_SEPERATOR; | |||
public static final String DATA_PREFIX = "KV" + ORIG_KEY_SEPERATOR; | |||
public static final String MERKLE_TREE_PREFIX = "MKL" + ORIG_KEY_SEPERATOR; | |||
public static final Bytes SN_PREFIX = Bytes.fromString("SN" + LedgerConsts.KEY_SEPERATOR); | |||
public static final Bytes DATA_PREFIX = Bytes.fromString("KV" + LedgerConsts.KEY_SEPERATOR); | |||
public static final Bytes MERKLE_TREE_PREFIX = Bytes.fromString("MKL" + LedgerConsts.KEY_SEPERATOR); | |||
private final Bytes snKeyPrefix; | |||
private final Bytes dataKeyPrefix; | |||
private final Bytes merkleKeyPrefix; | |||
@SuppressWarnings("unchecked") | |||
private static final DataEntry<Bytes, byte[]>[] EMPTY_ENTRIES = new DataEntry[0]; | |||
private BufferedKVStorage bufferedStorage; | |||
private VersioningKVStorage valueStorage; | |||
@@ -71,6 +75,18 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
*/ | |||
public MerkleDataSet(CryptoSetting setting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
this(setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage); | |||
} | |||
/** | |||
* 创建一个新的 MerkleDataSet; | |||
* | |||
* @param setting 密码设置; | |||
* @param exPolicyStorage 默克尔树的存储; | |||
* @param versioningStorage 数据的存储; | |||
*/ | |||
public MerkleDataSet(CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
// 缓冲对KV的写入; | |||
this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | |||
@@ -79,15 +95,15 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
// bufferedStorage); | |||
// this.snStorage = PrefixAppender.prefix(SN_PREFIX, (ExPolicyKVStorage) | |||
// bufferedStorage); | |||
snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); | |||
dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); | |||
snKeyPrefix = keyPrefix.concat(SN_PREFIX); | |||
dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); | |||
this.valueStorage = bufferedStorage; | |||
this.snStorage = bufferedStorage; | |||
// MerkleTree 本身是可缓冲的; | |||
// ExPolicyKVStorage merkleTreeStorage = | |||
// PrefixAppender.prefix(MERKLE_TREE_PREFIX, exPolicyStorage); | |||
merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX); | |||
merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); | |||
ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | |||
this.merkleTree = new MerkleTree(setting, merkleKeyPrefix, merkleTreeStorage); | |||
this.snGenerator = new MerkleSequenceSNGenerator(merkleTree); | |||
@@ -104,17 +120,33 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
*/ | |||
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, String keyPrefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
this(merkleRootHash, setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage, readonly); | |||
} | |||
/** | |||
* 从指定的 Merkle 根构建的 MerkleDataSet; | |||
* | |||
* @param dataStorage | |||
* @param defaultMerkleHashAlgorithm | |||
* @param verifyMerkleHashOnLoad | |||
* @param merkleTreeStorage | |||
* @param snGenerator | |||
*/ | |||
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, Bytes keyPrefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
// 缓冲对KV的写入; | |||
this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | |||
// 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击; | |||
snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); | |||
dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); | |||
// snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); | |||
// dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); | |||
snKeyPrefix = keyPrefix.concat(SN_PREFIX); | |||
dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); | |||
this.valueStorage = bufferedStorage; | |||
this.snStorage = bufferedStorage; | |||
// MerkleTree 本身是可缓冲的; | |||
merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX); | |||
merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); | |||
ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | |||
this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly); | |||
@@ -130,15 +162,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
this.readonly = true; | |||
} | |||
@Override | |||
public long getDataCount() { | |||
return merkleTree.getDataCount(); | |||
} | |||
/** | |||
* 返回理论上允许的最大数据索引; | |||
* | |||
* @return | |||
*/ | |||
public long getMaxIndex() { | |||
return merkleTree.getMaxSn(); | |||
} | |||
public byte[][] getLatestValues(int fromIndex, int count) { | |||
public byte[][] getLatestValues(long fromIndex, int count) { | |||
if (count > LedgerConsts.MAX_LIST_COUNT) { | |||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
} | |||
@@ -154,24 +192,41 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return values; | |||
} | |||
public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) { | |||
public DataEntry<Bytes, byte[]>[] getLatestDataEntries(long 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]; | |||
if (count == 0) { | |||
return EMPTY_ENTRIES; | |||
} | |||
@SuppressWarnings("unchecked") | |||
DataEntry<Bytes, byte[]>[] values = new DataEntry[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); | |||
values[i] = new VersioningKVData<Bytes, byte[]>(dataNode.getKey(), dataNode.getVersion(), bytesValue); | |||
} | |||
return values; | |||
} | |||
public DataEntry<Bytes, byte[]> getLatestDataEntry(long index) { | |||
if (index < 0 || index + 1 > merkleTree.getDataCount()) { | |||
throw new IllegalArgumentException("Index out of bound!"); | |||
} | |||
byte[] bytesValue; | |||
MerkleDataNode dataNode = merkleTree.getData(index); | |||
Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); | |||
DataEntry<Bytes, byte[]> entry = new VersioningKVData<Bytes, byte[]>(dataNode.getKey(), dataNode.getVersion(), | |||
bytesValue); | |||
return entry; | |||
} | |||
/** | |||
* get the data at the specific index; | |||
* | |||
@@ -192,32 +247,34 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
*/ | |||
public String getKeyAtIndex(int fromIndex) { | |||
MerkleDataNode dataNode = merkleTree.getData(fromIndex); | |||
return dataNode.getKey().toUTF8String(); | |||
} | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
* checking is passed.<br> | |||
* | |||
* The value of the key will be updated only if it's latest version equals the | |||
* specified version argument. <br> | |||
* If the key doesn't exist, it will be created when the version arg was -1. | |||
* <p> | |||
* 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. | |||
* @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> | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
*/ | |||
public long setValue(String key, byte[] value, long version) { | |||
return setValue(Bytes.fromString(key), value, version); | |||
} | |||
// TODO: 未去掉前缀; | |||
return dataNode.getKey().toUTF8String(); | |||
} | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, it will be created when the version arg was -1. | |||
// * <p> | |||
// * 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. | |||
// * @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> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// @Override | |||
// public long setValue(String key, byte[] value, long version) { | |||
// return setValue(Bytes.fromString(key), value, version); | |||
// } | |||
/** | |||
* Create or update the value associated the specified key if the version | |||
@@ -239,6 +296,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* If this operation fail by version checking or other reason, then | |||
* return -1; | |||
*/ | |||
@Override | |||
public long setValue(Bytes key, byte[] value, long version) { | |||
if (readonly) { | |||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||
@@ -336,18 +394,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return mdn.getVersion(); | |||
} | |||
/** | |||
* Return the specified version's value;<br> | |||
* | |||
* If the key with the specified version doesn't exist, then return null;<br> | |||
* If the version is specified to -1, then return the latest version's value; | |||
* | |||
* @param key | |||
* @param version | |||
*/ | |||
public byte[] getValue(String key, long version) { | |||
return getValue(Bytes.fromString(key), version); | |||
} | |||
// /** | |||
// * Return the specified version's value;<br> | |||
// * | |||
// * If the key with the specified version doesn't exist, then return null;<br> | |||
// * If the version is specified to -1, then return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// */ | |||
// @Override | |||
// public byte[] getValue(String key, long version) { | |||
// return getValue(Bytes.fromString(key), version); | |||
// } | |||
/** | |||
* Return the specified version's value;<br> | |||
@@ -358,6 +417,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* @param key | |||
* @param version | |||
*/ | |||
@Override | |||
public byte[] getValue(Bytes key, long version) { | |||
long latestVersion = getMerkleVersion(key); | |||
if (latestVersion < 0 || version > latestVersion) { | |||
@@ -370,15 +430,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return valueStorage.get(dataKey, version); | |||
} | |||
/** | |||
* Return the latest version's value; | |||
* | |||
* @param key | |||
* @return return null if not exist; | |||
*/ | |||
public byte[] getValue(String key) { | |||
return getValue(Bytes.fromString(key)); | |||
} | |||
// /** | |||
// * Return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// @Override | |||
// public byte[] getValue(String key) { | |||
// return getValue(Bytes.fromString(key)); | |||
// } | |||
/** | |||
* Return the latest version's value; | |||
@@ -386,6 +447,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* @param key | |||
* @return return null if not exist; | |||
*/ | |||
@Override | |||
public byte[] getValue(Bytes key) { | |||
long latestVersion = getMerkleVersion(key); | |||
if (latestVersion < 0) { | |||
@@ -395,16 +457,17 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
return valueStorage.get(dataKey, latestVersion); | |||
} | |||
/** | |||
* 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 getMerkleVersion(Bytes.fromString(key)); | |||
} | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// @Override | |||
// public long getVersion(String key) { | |||
// return getMerkleVersion(Bytes.fromString(key)); | |||
// } | |||
/** | |||
* Return the latest version entry associated the specified key; If the key | |||
@@ -413,33 +476,46 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
* @param key | |||
* @return | |||
*/ | |||
@Override | |||
public long getVersion(Bytes key) { | |||
return getMerkleVersion(key); | |||
} | |||
public VersioningKVEntry getDataEntry(String key) { | |||
return getDataEntry(Bytes.fromString(key)); | |||
} | |||
// @Override | |||
// public VersioningKVEntry<String, byte[]> getDataEntry(String key) { | |||
// return getDataEntry(key, -1); | |||
// } | |||
/** | |||
* | |||
* @param key | |||
* @return Null if the key doesn't exist! | |||
*/ | |||
public VersioningKVEntry getDataEntry(Bytes key) { | |||
long latestVersion = getMerkleVersion(key); | |||
if (latestVersion < 0) { | |||
return null; | |||
} | |||
Bytes dataKey = encodeDataKey(key); | |||
byte[] value = valueStorage.get(dataKey, latestVersion); | |||
if (value == null) { | |||
return null; | |||
} | |||
return new VersioningKVData(key, latestVersion, value); | |||
} | |||
@Override | |||
public DataEntry<Bytes, byte[]> getDataEntry(Bytes key) { | |||
return getDataEntry(key, -1); | |||
} | |||
// @Override | |||
// public VersioningKVEntry<String, byte[]> getDataEntry(String key, long version) { | |||
// Bytes keyBytes = Bytes.fromString(key); | |||
// long latestVersion = getMerkleVersion(keyBytes); | |||
// if (latestVersion < 0 || version > latestVersion) { | |||
// // key not exist, or the specified version is out of the latest version indexed | |||
// // by the current merkletree; | |||
// return null; | |||
// } | |||
// version = version < 0 ? latestVersion : version; | |||
// Bytes dataKey = encodeDataKey(keyBytes); | |||
// byte[] value = valueStorage.get(dataKey, version); | |||
// if (value == null) { | |||
// return null; | |||
// } | |||
// return new VersioningKVData<String, byte[]>(key, version, value); | |||
// } | |||
public VersioningKVEntry getDataEntry(Bytes key, long version) { | |||
@Override | |||
public DataEntry<Bytes, byte[]> getDataEntry(Bytes key, long version) { | |||
long latestVersion = getMerkleVersion(key); | |||
if (latestVersion < 0 || version > latestVersion) { | |||
// key not exist, or the specified version is out of the latest version indexed | |||
@@ -452,11 +528,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
if (value == null) { | |||
return null; | |||
} | |||
return new VersioningKVData(key, version, value); | |||
return new VersioningKVData<Bytes, byte[]>(key, version, value); | |||
} | |||
@Override | |||
public DataIterator<Bytes, byte[]> iterator() { | |||
return new AscDataInterator(getDataCount()); | |||
} | |||
@Override | |||
public DataIterator<Bytes, byte[]> iteratorDesc() { | |||
return new DescDataInterator(getDataCount()); | |||
} | |||
public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | |||
VersioningKVEntry dataEntry = getDataEntry(key, version); | |||
DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version); | |||
if (dataEntry == null) { | |||
return null; | |||
} | |||
@@ -465,7 +551,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
} | |||
public MerkleDataEntry getMerkleEntry(Bytes key) { | |||
VersioningKVEntry dataEntry = getDataEntry(key); | |||
DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key); | |||
if (dataEntry == null) { | |||
return null; | |||
} | |||
@@ -492,23 +578,23 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
} | |||
/** | |||
* A wrapper for {@link VersioningKVEntry} and {@link MerkleProof}; | |||
* A wrapper for {@link DataEntry} and {@link MerkleProof}; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private static class MerkleDataEntryWrapper implements MerkleDataEntry { | |||
private VersioningKVEntry data; | |||
private DataEntry<Bytes, byte[]> data; | |||
private MerkleProof proof; | |||
public MerkleDataEntryWrapper(VersioningKVEntry data, MerkleProof proof) { | |||
public MerkleDataEntryWrapper(DataEntry<Bytes, byte[]> data, MerkleProof proof) { | |||
this.data = data; | |||
this.proof = proof; | |||
} | |||
@Override | |||
public VersioningKVEntry getData() { | |||
public DataEntry<Bytes, byte[]> getData() { | |||
return data; | |||
} | |||
@@ -536,4 +622,119 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||
merkleTree.cancel(); | |||
snGenerator = new MerkleSequenceSNGenerator(merkleTree); | |||
} | |||
// ---------------------------------------------------------- | |||
private class AscDataInterator implements DataIterator<Bytes, byte[]> { | |||
private final long total; | |||
private long cursor = 0; | |||
public AscDataInterator(long total) { | |||
this.total = total; | |||
} | |||
@Override | |||
public void skip(long count) { | |||
cursor = nextCursor(count); | |||
} | |||
private long nextCursor(long skippingCount) { | |||
long c = cursor + skippingCount; | |||
return c > total ? total : c; | |||
} | |||
@Override | |||
public DataEntry<Bytes, byte[]> next() { | |||
if (hasNext()) { | |||
DataEntry<Bytes, byte[]> entry = getLatestDataEntry(cursor); | |||
cursor = nextCursor(1); | |||
return entry; | |||
} | |||
return null; | |||
} | |||
@Override | |||
public DataEntry<Bytes, byte[]>[] next(int count) { | |||
if (hasNext()) { | |||
long from = cursor; | |||
long nextCursor = nextCursor(count); | |||
long c = nextCursor - cursor; | |||
if (c > LedgerConsts.MAX_LIST_COUNT) { | |||
throw new IllegalArgumentException( | |||
"Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
} | |||
DataEntry<Bytes, byte[]>[] entries = getLatestDataEntries(from, (int) c); | |||
cursor = nextCursor; | |||
return entries; | |||
} | |||
return EMPTY_ENTRIES; | |||
} | |||
@Override | |||
public boolean hasNext() { | |||
return cursor < total; | |||
} | |||
} | |||
private class DescDataInterator implements DataIterator<Bytes, byte[]> { | |||
private final long total; | |||
private long cursor; | |||
public DescDataInterator(long total) { | |||
this.total = total; | |||
this.cursor = total - 1; | |||
} | |||
@Override | |||
public void skip(long count) { | |||
cursor = nextCursor(count); | |||
} | |||
private long nextCursor(long skippingCount) { | |||
long c = cursor - skippingCount; | |||
return c < 0 ? -1 : c; | |||
} | |||
@Override | |||
public DataEntry<Bytes, byte[]> next() { | |||
if (hasNext()) { | |||
DataEntry<Bytes, byte[]> entry = getLatestDataEntry(cursor); | |||
cursor = nextCursor(1); | |||
return entry; | |||
} | |||
return null; | |||
} | |||
@Override | |||
public DataEntry<Bytes, byte[]>[] next(int count) { | |||
if (hasNext()) { | |||
long nextCursor = nextCursor(count); | |||
long from = nextCursor + 1; | |||
long c = cursor - nextCursor; | |||
if (c > LedgerConsts.MAX_LIST_COUNT) { | |||
throw new IllegalArgumentException( | |||
"Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
} | |||
DataEntry<Bytes, byte[]>[] entries = getLatestDataEntries(from, (int) c); | |||
// reverse; | |||
ArrayUtils.reverse(entries); | |||
cursor = nextCursor; | |||
return entries; | |||
} | |||
return EMPTY_ENTRIES; | |||
} | |||
@Override | |||
public boolean hasNext() { | |||
return cursor < total; | |||
} | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
@@ -15,7 +15,7 @@ import com.jd.blockchain.utils.Bytes; | |||
public class OpeningAccessPolicy implements AccountAccessPolicy { | |||
@Override | |||
public boolean checkDataWriting(AccountHeader account) { | |||
public boolean checkDataWriting(BlockchainIdentity account) { | |||
return true; | |||
} | |||
@@ -28,7 +28,7 @@ public class ParticipantDataset implements Transactional, MerkleProvable, Partic | |||
public ParticipantDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, verStorage, readonly); | |||
} | |||
@Override | |||
@@ -14,10 +14,10 @@ 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; | |||
import com.jd.blockchain.utils.DataEntry; | |||
public class RolePrivilegeDataset implements Transactional, MerkleProvable, RolePrivilegeSettings { | |||
@@ -30,7 +30,8 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role | |||
public RolePrivilegeDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, | |||
verStorage, readonly); | |||
} | |||
@Override | |||
@@ -255,7 +256,7 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role | |||
public RolePrivileges getRolePrivilege(String roleName) { | |||
// 只返回最新版本; | |||
Bytes key = encodeKey(roleName); | |||
VersioningKVEntry kv = dataset.getDataEntry(key); | |||
DataEntry<Bytes, byte[]> kv = dataset.getDataEntry(key); | |||
if (kv == null) { | |||
return null; | |||
} | |||
@@ -265,7 +266,7 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role | |||
@Override | |||
public RolePrivileges[] getRolePrivileges(int index, int count) { | |||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(index, count); | |||
DataEntry<Bytes, byte[]>[] kvEntries = dataset.getLatestDataEntries(index, count); | |||
RolePrivileges[] pns = new RolePrivileges[kvEntries.length]; | |||
PrivilegeSet privilege; | |||
for (int i = 0; i < pns.length; i++) { | |||
@@ -1,12 +1,5 @@ | |||
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>(); | |||
@@ -88,7 +88,8 @@ public class TransactionSet implements Transactional, TransactionQuery { | |||
public TransactionSet(HashDigest txRootHash, CryptoSetting setting, String keyPrefix, | |||
ExPolicyKVStorage merkleTreeStorage, VersioningKVStorage dataStorage, boolean readonly) { | |||
this.txStatePrefix = Bytes.fromString(keyPrefix + TX_STATE_PREFIX); | |||
this.txSet = new MerkleDataSet(txRootHash, setting, keyPrefix, merkleTreeStorage, dataStorage, readonly); | |||
this.txSet = new MerkleDataSet(txRootHash, setting, Bytes.fromString(keyPrefix), merkleTreeStorage, dataStorage, | |||
readonly); | |||
} | |||
/** | |||
@@ -1,9 +1,9 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -13,72 +13,73 @@ import com.jd.blockchain.utils.Bytes; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccount implements UserInfo { | |||
public class UserAccount extends AccountDecorator implements UserInfo { // implements UserInfo { | |||
private static final Bytes USER_INFO_PREFIX = Bytes.fromString("PROP" + LedgerConsts.KEY_SEPERATOR); | |||
private static final String USER_INFO_PREFIX = "PROP" + LedgerConsts.KEY_SEPERATOR; | |||
private static final Bytes DATA_PUB_KEY = Bytes.fromString("DATA-PUBKEY"); | |||
private static final String DATA_PUB_KEY = "DATA-PUBKEY"; | |||
private MerkleAccount baseAccount; | |||
public UserAccount(CompositeAccount baseAccount) { | |||
super(baseAccount); | |||
} | |||
private PubKey dataPubKey; | |||
@Override | |||
public Bytes getAddress() { | |||
return baseAccount.getAddress(); | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return baseAccount.getPubKey(); | |||
return getID().getPubKey(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return baseAccount.getRootHash(); | |||
} | |||
public UserAccount(MerkleAccount baseAccount) { | |||
this.baseAccount = baseAccount; | |||
} | |||
public PubKey getDataPubKey() { | |||
BytesValue pkBytes = baseAccount.getBytes(DATA_PUB_KEY); | |||
if (pkBytes == null) { | |||
return null; | |||
if (dataPubKey == null) { | |||
BytesValue pkBytes = getHeaders().getValue(DATA_PUB_KEY); | |||
if (pkBytes == null) { | |||
return null; | |||
} | |||
dataPubKey = new PubKey(pkBytes.getBytes().toBytes()); | |||
} | |||
return new PubKey(pkBytes.getValue().toBytes()); | |||
return dataPubKey; | |||
} | |||
public long setDataPubKey(PubKey pubKey) { | |||
byte[] pkBytes = pubKey.toBytes(); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1); | |||
public void setDataPubKey(PubKey pubKey) { | |||
long version = getHeaders().getVersion(DATA_PUB_KEY); | |||
setDataPubKey(pubKey, version); | |||
} | |||
public long setDataPubKey(PubKey pubKey, long version) { | |||
byte[] pkBytes = pubKey.toBytes(); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version); | |||
public void setDataPubKey(PubKey pubKey, long version) { | |||
TypedValue value = TypedValue.fromPubKey(dataPubKey); | |||
long newVersion = getHeaders().setValue(DATA_PUB_KEY, value, version); | |||
if (newVersion > -1) { | |||
dataPubKey = pubKey; | |||
} else { | |||
throw new LedgerException("Data public key was updated failed!"); | |||
} | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
return setProperty(Bytes.fromString(key), value, version); | |||
return getHeaders().setValue(encodePropertyKey(key), TypedValue.fromText(value), version); | |||
} | |||
public long setProperty(Bytes key, String value, long version) { | |||
return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version); | |||
public String getProperty(String key) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key)); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
public String getProperty(Bytes key) { | |||
BytesValue value = baseAccount.getBytes(encodePropertyKey(key)); | |||
return value == null ? null : value.getValue().toUTF8String(); | |||
public String getProperty(String key, long version) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key), version); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
public String getProperty(Bytes key, long version) { | |||
BytesValue value = baseAccount.getBytes(encodePropertyKey(key), version); | |||
return value == null ? null : value.getValue().toUTF8String(); | |||
private String encodePropertyKey(String key) { | |||
return USER_INFO_PREFIX+key; | |||
} | |||
private Bytes encodePropertyKey(Bytes key) { | |||
// return key.concatTo(USER_INFO_PREFIX); | |||
return USER_INFO_PREFIX.concat(key); | |||
} | |||
} |
@@ -2,7 +2,7 @@ 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.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
@@ -21,19 +21,20 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
public UserAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage simpleStorage, | |||
VersioningKVStorage versioningStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, keyPrefix, simpleStorage, versioningStorage, accessPolicy); | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(keyPrefix), simpleStorage, versioningStorage, | |||
accessPolicy); | |||
} | |||
public UserAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, | |||
accessPolicy); | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(keyPrefix), exStorage, | |||
verStorage, readonly, accessPolicy); | |||
} | |||
@Override | |||
public AccountHeader[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex,count); | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
/** | |||
@@ -49,7 +50,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@@ -63,7 +64,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
public MerkleProof getProof(Bytes key) { | |||
return accountSet.getProof(key); | |||
} | |||
@Override | |||
public UserAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
@@ -71,7 +72,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
@Override | |||
public UserAccount getAccount(Bytes address) { | |||
MerkleAccount baseAccount = accountSet.getAccount(address); | |||
CompositeAccount baseAccount = accountSet.getAccount(address); | |||
return new UserAccount(baseAccount); | |||
} | |||
@@ -82,7 +83,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
@Override | |||
public UserAccount getAccount(Bytes address, long version) { | |||
MerkleAccount baseAccount = accountSet.getAccount(address, version); | |||
CompositeAccount baseAccount = accountSet.getAccount(address, version); | |||
return new UserAccount(baseAccount); | |||
} | |||
@@ -93,14 +94,12 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||
* | |||
* 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; | |||
* | |||
* @param address | |||
* 区块链地址; | |||
* @param pubKey | |||
* 公钥; | |||
* @param address 区块链地址; | |||
* @param pubKey 公钥; | |||
* @return 注册成功的用户对象; | |||
*/ | |||
public UserAccount register(Bytes address, PubKey pubKey) { | |||
MerkleAccount baseAccount = accountSet.register(address, pubKey); | |||
CompositeAccount baseAccount = accountSet.register(address, pubKey); | |||
return new UserAccount(baseAccount); | |||
} | |||
@@ -13,10 +13,10 @@ import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.UserRoles; | |||
import com.jd.blockchain.ledger.UserAuthorizationSettings; | |||
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; | |||
import com.jd.blockchain.utils.DataEntry; | |||
/** | |||
* User-Role authorization data set; | |||
@@ -35,7 +35,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho | |||
public UserRoleDataset(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, Bytes.fromString(prefix), exPolicyStorage, verStorage, readonly); | |||
} | |||
@Override | |||
@@ -168,7 +168,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho | |||
@Override | |||
public UserRoles getUserRoles(Bytes userAddress) { | |||
// 只返回最新版本; | |||
VersioningKVEntry kv = dataset.getDataEntry(userAddress); | |||
DataEntry<Bytes, byte[]> kv = dataset.getDataEntry(userAddress); | |||
if (kv == null) { | |||
return null; | |||
} | |||
@@ -178,7 +178,7 @@ public class UserRoleDataset implements Transactional, MerkleProvable, UserAutho | |||
@Override | |||
public UserRoles[] getUserRoles() { | |||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); | |||
DataEntry<Bytes, byte[]>[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); | |||
UserRoles[] pns = new UserRoles[kvEntries.length]; | |||
RoleSet roleset; | |||
for (int i = 0; i < pns.length; i++) { | |||
@@ -5,7 +5,24 @@ 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.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
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.Operation; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.ledger.core.OperationHandleContext; | |||
import com.jd.blockchain.transaction.BlockchainQueryService; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; | |||
@@ -150,22 +167,22 @@ public class ContractLedgerContext implements LedgerContext { | |||
} | |||
@Override | |||
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | |||
public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { | |||
return innerQueryService.getDataAccount(ledgerHash, address); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
return innerQueryService.getDataEntries(ledgerHash, address, keys); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count); | |||
} | |||
@@ -182,17 +199,17 @@ public class ContractLedgerContext implements LedgerContext { | |||
// ---------------------------user()---------------------------- | |||
@Override | |||
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
return innerQueryService.getUsers(ledgerHash, fromIndex, count); | |||
} | |||
@Override | |||
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
return innerQueryService.getDataAccounts(ledgerHash, fromIndex, count); | |||
} | |||
@Override | |||
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
return innerQueryService.getContractAccounts(ledgerHash, fromIndex, count); | |||
} | |||
@@ -268,7 +285,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
BytesValue bytesValue = TypedValue.fromText(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -276,7 +293,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -284,7 +301,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromInt64(value); | |||
BytesValue bytesValue = TypedValue.fromInt64(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -301,7 +318,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromJSON(value); | |||
BytesValue bytesValue = TypedValue.fromJSON(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -309,7 +326,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromXML(value); | |||
BytesValue bytesValue = TypedValue.fromXML(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -317,7 +334,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -325,7 +342,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromImage(value); | |||
BytesValue bytesValue = TypedValue.fromImage(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -333,7 +350,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
BytesValue bytesValue = TypedValue.fromTimestamp(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -5,6 +5,7 @@ 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.TypedValue; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerQuery; | |||
@@ -37,7 +38,7 @@ public class DataAccountKVSetOperationHandle extends AbstractLedgerOperationHand | |||
KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); | |||
long v = -1L; | |||
for (KVWriteEntry kvw : writeSet) { | |||
v = account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); | |||
v = account.getDataset().setValue(kvw.getKey(), TypedValue.wrap(kvw.getValue()), kvw.getExpectedVersion()); | |||
if (v < 0) { | |||
throw new DataVersionConflictException(); | |||
} | |||
@@ -3,7 +3,7 @@ package test.com.jd.blockchain.ledger; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractLifecycleAware; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class TxTestContractImpl implements TxTestContract, ContractLifecycleAware, EventProcessingAware { | |||
@@ -16,7 +16,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar | |||
@Override | |||
public boolean testReadable() { | |||
KVDataEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||
TypedKVEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||
dataAddress.toBase58(), KEY)[0]; | |||
String text1 = (String) v1.getValue(); | |||
System.out.printf("k1=%s, version=%s \r\n", text1, v1.getVersion()); | |||
@@ -26,7 +26,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar | |||
System.out.printf("new value = %s\r\n", newValue); | |||
eventContext.getLedger().dataAccount(dataAddress).setText(KEY, newValue, v1.getVersion()); | |||
KVDataEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||
TypedKVEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||
dataAddress.toBase58(), KEY)[0]; | |||
System.out.printf("---- read new value ----\r\nk1=%s, version=%s \r\n", v2.getValue(), v2.getVersion()); | |||
@@ -14,11 +14,12 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.core.MerkleAccountSet; | |||
import com.jd.blockchain.ledger.core.MerkleAccount; | |||
import com.jd.blockchain.ledger.core.CompositeAccount; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.core.MerkleAccountSet; | |||
import com.jd.blockchain.ledger.core.OpeningAccessPolicy; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class AccountSetTest { | |||
@@ -43,12 +44,13 @@ public class AccountSetTest { | |||
cryptoConf.setHashAlgorithm(ClassicAlgorithm.SHA256); | |||
String keyPrefix = ""; | |||
MerkleAccountSet accset = new MerkleAccountSet(cryptoConf, keyPrefix, storage, storage, accessPolicy); | |||
MerkleAccountSet accset = new MerkleAccountSet(cryptoConf, Bytes.fromString(keyPrefix), storage, storage, accessPolicy); | |||
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); | |||
accset.register(userKey.getAddress(), userKey.getPubKey()); | |||
MerkleAccount userAcc = accset.getAccount(userKey.getAddress()); | |||
//尚未提交之前,可以检索到账户的存在,但版本仍然标记为 -1; | |||
CompositeAccount userAcc = accset.getAccount(userKey.getAddress()); | |||
assertNotNull(userAcc); | |||
assertTrue(accset.contains(userKey.getAddress())); | |||
@@ -56,13 +58,13 @@ public class AccountSetTest { | |||
HashDigest rootHash = accset.getRootHash(); | |||
assertNotNull(rootHash); | |||
MerkleAccountSet reloadAccSet = new MerkleAccountSet(rootHash, cryptoConf, keyPrefix, storage, storage, true, accessPolicy); | |||
MerkleAccount reloadUserAcc = reloadAccSet.getAccount(userKey.getAddress()); | |||
MerkleAccountSet reloadAccSet = new MerkleAccountSet(rootHash, cryptoConf, Bytes.fromString(keyPrefix), storage, storage, true, accessPolicy); | |||
CompositeAccount reloadUserAcc = reloadAccSet.getAccount(userKey.getAddress()); | |||
assertNotNull(reloadUserAcc); | |||
assertTrue(reloadAccSet.contains(userKey.getAddress())); | |||
assertEquals(userAcc.getAddress(), reloadUserAcc.getAddress()); | |||
assertEquals(userAcc.getPubKey(), reloadUserAcc.getPubKey()); | |||
assertEquals(userAcc.getID().getAddress(), reloadUserAcc.getID().getAddress()); | |||
assertEquals(userAcc.getID().getPubKey(), reloadUserAcc.getID().getPubKey()); | |||
} | |||
} |
@@ -2,6 +2,7 @@ package test.com.jd.blockchain.ledger.core; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import org.junit.Test; | |||
@@ -12,9 +13,9 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.core.MerkleAccount; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.core.MerkleAccount; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -48,38 +49,39 @@ public class BaseAccountTest { | |||
BlockchainKeypair bck = BlockchainKeyGenerator.getInstance().generate(); | |||
// 新建账户; | |||
MerkleAccount baseAccount = new MerkleAccount(bck.getIdentity(), cryptoConf, keyPrefix, testStorage, testStorage); | |||
assertFalse(baseAccount.isUpdated());// 空的账户; | |||
MerkleAccount baseAccount = new MerkleAccount(bck.getIdentity(), cryptoConf, Bytes.fromString(keyPrefix), | |||
testStorage, testStorage); | |||
assertTrue(baseAccount.isUpdated());//初始化新账户时,先写入PubKey; | |||
assertFalse(baseAccount.isReadonly()); | |||
// 在空白状态下写入数据; | |||
long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0); | |||
long v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), 0); | |||
// 预期失败; | |||
assertEquals(-1, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1); | |||
v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), 1); | |||
// 预期失败; | |||
assertEquals(-1, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1); | |||
v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A"), -1); | |||
// 预期成功; | |||
assertEquals(0, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1); | |||
v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A-1"), -1); | |||
// 已经存在版本,指定版本号-1,预期导致失败; | |||
assertEquals(-1, v); | |||
baseAccount.commit(); | |||
v = 0; | |||
for (int i = 0; i < 10; i++) { | |||
long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v); | |||
long s = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A_" + i), v); | |||
baseAccount.commit(); | |||
// 预期成功; | |||
assertEquals(v + 1, s); | |||
v++; | |||
} | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1); | |||
v = baseAccount.getDataset().setValue("A", TypedValue.fromText("VALUE_A_" + v), v + 1); | |||
// 预期成功; | |||
assertEquals(-1, v); | |||
@@ -16,14 +16,35 @@ import static org.mockito.Mockito.when; | |||
import java.io.InputStream; | |||
import java.util.Random; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.ledger.*; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.EndpointRequest; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.ParticipantRegisterOperation; | |||
import com.jd.blockchain.ledger.ParticipantStateUpdateOperation; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionContentBody; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.ledger.core.DefaultOperationHandleRegisteration; | |||
import com.jd.blockchain.ledger.core.LedgerDataQuery; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
@@ -43,6 +64,8 @@ import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.transaction.BooleanValueHolder; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import test.com.jd.blockchain.ledger.TxTestContract; | |||
import test.com.jd.blockchain.ledger.TxTestContractImpl; | |||
@@ -132,7 +155,7 @@ public class ContractInvokingTest { | |||
assertEquals(1, opResults.length); | |||
assertEquals(0, opResults[0].getIndex()); | |||
byte[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class); | |||
byte[] expectedRetnBytes = BinaryProtocol.encode(TypedValue.fromInt64(issueAmount), BytesValue.class); | |||
byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); | |||
assertArrayEquals(expectedRetnBytes, reallyRetnBytes); | |||
@@ -218,9 +241,9 @@ public class ContractInvokingTest { | |||
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); | |||
txResultHandle.commit(); | |||
BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getBytes(key, | |||
BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getValue(key, | |||
-1); | |||
System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getValue().toUTF8String()); | |||
System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getBytes().toUTF8String()); | |||
boolean readable = readableHolder.get(); | |||
assertTrue(readable); | |||
@@ -278,14 +301,14 @@ public class ContractInvokingTest { | |||
} | |||
}); | |||
// 预期数据都能够正常写入; | |||
KVDataEntry kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", | |||
DataEntry<String, TypedValue> kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", | |||
0); | |||
KVDataEntry kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K2", | |||
DataEntry<String, TypedValue> kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", | |||
0); | |||
assertEquals(0, kv1.getVersion()); | |||
assertEquals(0, kv2.getVersion()); | |||
assertEquals("V1-0", kv1.getValue()); | |||
assertEquals("V2-0", kv2.getValue()); | |||
assertEquals("V1-0", kv1.getValue().stringValue()); | |||
assertEquals("V2-0", kv2.getValue().stringValue()); | |||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||
buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() { | |||
@@ -299,12 +322,12 @@ public class ContractInvokingTest { | |||
} | |||
}); | |||
// 预期数据都能够正常写入; | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1); | |||
kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K2", 1); | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 1); | |||
kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", 1); | |||
assertEquals(1, kv1.getVersion()); | |||
assertEquals(1, kv2.getVersion()); | |||
assertEquals("V1-1", kv1.getValue()); | |||
assertEquals("V2-1", kv2.getValue()); | |||
assertEquals("V1-1", kv1.getValue().stringValue()); | |||
assertEquals("V2-1", kv2.getValue().stringValue()); | |||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||
buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() { | |||
@@ -314,16 +337,17 @@ public class ContractInvokingTest { | |||
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K1", "V1-2", | |||
1); | |||
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K2", "V2-2", | |||
0); | |||
0);//预期会回滚; | |||
} | |||
}); | |||
// 预期数据都能够正常写入; | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1); | |||
// 预期数据回滚,账本没有发生变更; | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 1); | |||
assertEquals(1, kv1.getVersion()); | |||
assertEquals("V1-1", kv1.getValue()); | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataEntry("K1", 2); | |||
assertEquals(-1, kv1.getVersion()); | |||
assertEquals(null, kv1.getValue()); | |||
assertEquals("V1-1", kv1.getValue().stringValue()); | |||
kv1 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K1", 2); | |||
assertNull(kv1); | |||
kv2 = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getDataset().getDataEntry("K2", 1); | |||
assertEquals(1, kv2.getVersion()); | |||
} | |||
@@ -1,22 +1,12 @@ | |||
package test.com.jd.blockchain.ledger.core; | |||
import static org.junit.Assert.assertEquals; | |||
import java.util.Random; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
import com.jd.blockchain.crypto.service.sm.SMAlgorithm; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.ledger.core.MerkleAccountSet; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* Created by zhangshuang3 on 2018/9/3. | |||
@@ -35,27 +25,27 @@ public class LedgerAccountTest { | |||
rand.nextBytes(seed); | |||
rand.nextBytes(settingValue); | |||
rand.nextBytes(rawDigestBytes); | |||
DataContractRegistry.register(AccountHeader.class); | |||
DataContractRegistry.register(BlockchainIdentity.class); | |||
DataContractRegistry.register(UserInfo.class); | |||
} | |||
@Test | |||
public void testSerialize_AccountHeader() { | |||
String address = "xxxxxxxxxxxx"; | |||
PubKey pubKey = new PubKey(SMAlgorithm.SM2, rawDigestBytes); | |||
HashDigest hashDigest = new HashDigest(ClassicAlgorithm.SHA256, rawDigestBytes); | |||
MerkleAccountSet.AccountHeaderData accountHeaderData = new MerkleAccountSet.AccountHeaderData(Bytes.fromString(address), | |||
pubKey, hashDigest); | |||
// encode and decode | |||
byte[] encodeBytes = BinaryProtocol.encode(accountHeaderData, AccountHeader.class); | |||
AccountHeader deAccountHeaderData = BinaryProtocol.decode(encodeBytes); | |||
// verify start | |||
assertEquals(accountHeaderData.getAddress(), deAccountHeaderData.getAddress()); | |||
assertEquals(accountHeaderData.getPubKey(), deAccountHeaderData.getPubKey()); | |||
assertEquals(accountHeaderData.getRootHash(), deAccountHeaderData.getRootHash()); | |||
} | |||
// @Test | |||
// public void testSerialize_AccountHeader() { | |||
// String address = "xxxxxxxxxxxx"; | |||
// PubKey pubKey = new PubKey(SMAlgorithm.SM2, rawDigestBytes); | |||
// HashDigest hashDigest = new HashDigest(ClassicAlgorithm.SHA256, rawDigestBytes); | |||
// MerkleAccountSet.AccountHeaderData accountHeaderData = new MerkleAccountSet.AccountHeaderData(Bytes.fromString(address), | |||
// pubKey, hashDigest); | |||
// | |||
// // encode and decode | |||
// byte[] encodeBytes = BinaryProtocol.encode(accountHeaderData, AccountHeader.class); | |||
// AccountHeader deAccountHeaderData = BinaryProtocol.decode(encodeBytes); | |||
// | |||
// // verify start | |||
// assertEquals(accountHeaderData.getAddress(), deAccountHeaderData.getAddress()); | |||
// assertEquals(accountHeaderData.getPubKey(), deAccountHeaderData.getPubKey()); | |||
// assertEquals(accountHeaderData.getRootHash(), deAccountHeaderData.getRootHash()); | |||
// } | |||
} |
@@ -8,12 +8,9 @@ import org.junit.Before; | |||
import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.CryptoProvider; | |||
import com.jd.blockchain.crypto.SignatureFunction; | |||
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
@@ -25,7 +22,7 @@ import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.LedgerDataset; | |||
import com.jd.blockchain.ledger.core.LedgerEditor; | |||
@@ -33,11 +30,6 @@ import com.jd.blockchain.ledger.core.LedgerTransactionContext; | |||
import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; | |||
import com.jd.blockchain.ledger.core.UserAccount; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.transaction.ConsensusParticipantData; | |||
import com.jd.blockchain.transaction.LedgerInitData; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.net.NetworkAddress; | |||
public class LedgerEditorTest { | |||
@@ -102,7 +94,7 @@ public class LedgerEditorTest { | |||
DataAccount dataAccount = ldgDS.getDataAccountSet().register(dataKP.getAddress(), dataKP.getPubKey(), null); | |||
dataAccount.setBytes(Bytes.fromString("A"), "abc", -1); | |||
dataAccount.getDataset().setValue("A", TypedValue.fromText("abc"), -1); | |||
LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); | |||
LedgerBlock block = ldgEdt.prepare(); | |||
@@ -115,9 +107,9 @@ public class LedgerEditorTest { | |||
assertEquals(0, block.getHeight()); | |||
// 验证数据读写的一致性; | |||
BytesValue bytes = dataAccount.getBytes("A"); | |||
BytesValue bytes = dataAccount.getDataset().getValue("A"); | |||
assertEquals(DataType.TEXT, bytes.getType()); | |||
String textValue = bytes.getValue().toUTF8String(); | |||
String textValue = bytes.getBytes().toUTF8String(); | |||
assertEquals("abc", textValue); | |||
} | |||
@@ -44,12 +44,18 @@ public class LedgerTestUtils { | |||
partiKeys[1] = BlockchainKeyGenerator.getInstance().generate(); | |||
return createLedgerInitSetting(partiKeys); | |||
} | |||
public static LedgerInitSetting createLedgerInitSetting(BlockchainKeypair[] partiKeys) { | |||
public static CryptoProvider[] getContextProviders() { | |||
CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; | |||
for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { | |||
supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); | |||
} | |||
return supportedProviders; | |||
} | |||
public static LedgerInitSetting createLedgerInitSetting(BlockchainKeypair[] partiKeys) { | |||
CryptoProvider[] supportedProviders =getContextProviders(); | |||
CryptoConfig defCryptoSetting = new CryptoConfig(); | |||
defCryptoSetting.setSupportedProviders(supportedProviders); | |||
@@ -0,0 +1,58 @@ | |||
package test.com.jd.blockchain.ledger.core; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import org.junit.Test; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.core.CompositeAccount; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.core.MerkleAccountSet; | |||
import com.jd.blockchain.ledger.core.OpeningAccessPolicy; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class MerkleAccountSetTest { | |||
@Test | |||
public void testRegister() { | |||
final OpeningAccessPolicy POLICY = new OpeningAccessPolicy(); | |||
final MemoryKVStorage STORAGE = new MemoryKVStorage(); | |||
Bytes KEY_PREFIX = Bytes.fromString("/ACCOUNT"); | |||
CryptoConfig cryptoConfig = new CryptoConfig(); | |||
cryptoConfig.setSupportedProviders(LedgerTestUtils.getContextProviders()); | |||
cryptoConfig.setAutoVerifyHash(true); | |||
cryptoConfig.setHashAlgorithm(Crypto.getAlgorithm("SHA256")); | |||
MerkleAccountSet accountset = new MerkleAccountSet(cryptoConfig, KEY_PREFIX, STORAGE, STORAGE, POLICY); | |||
BlockchainKeypair key1 = BlockchainKeyGenerator.getInstance().generate(); | |||
accountset.register(key1.getIdentity()); | |||
accountset.commit(); | |||
CompositeAccount acc1 = accountset.getAccount(key1.getAddress()); | |||
assertNotNull(acc1); | |||
assertEquals(0, accountset.getVersion(key1.getAddress())); | |||
acc1.getDataset().setValue("K1", TypedValue.fromText("V0"), -1); | |||
TypedValue v1 = acc1.getDataset().getValue("K1"); | |||
assertNotNull(v1); | |||
assertEquals(0, acc1.getDataset().getVersion("K1")); | |||
accountset.commit(); | |||
v1 = acc1.getDataset().getValue("K1"); | |||
assertNotNull(v1); | |||
assertEquals(0, acc1.getDataset().getVersion("K1")); | |||
} | |||
} |
@@ -23,9 +23,11 @@ import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.ledger.core.MerkleDataSet; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.Dataset; | |||
import com.jd.blockchain.utils.DatasetHelper; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
public class MerkleDataSetTest { | |||
@@ -53,9 +55,9 @@ public class MerkleDataSetTest { | |||
MemoryKVStorage storage = new MemoryKVStorage(); | |||
MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); | |||
mds.setValue("A", "A".getBytes(), -1); | |||
mds.setValue("B", "B".getBytes(), -1); | |||
mds.setValue("C", "C".getBytes(), -1); | |||
mds.setValue(Bytes.fromString("A"), "A".getBytes(), -1); | |||
mds.setValue(Bytes.fromString("B"), "B".getBytes(), -1); | |||
mds.setValue(Bytes.fromString("C"), "C".getBytes(), -1); | |||
mds.commit(); | |||
@@ -85,22 +87,23 @@ public class MerkleDataSetTest { | |||
MemoryKVStorage storage = new MemoryKVStorage(); | |||
MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); | |||
mds.setValue("A", "A".getBytes(), -1); | |||
mds.setValue("B", "B".getBytes(), -1); | |||
mds.setValue("C", "C".getBytes(), -1); | |||
Dataset<String, byte[]> ds = DatasetHelper.map(mds); | |||
ds.setValue("A", "A".getBytes(), -1); | |||
ds.setValue("B", "B".getBytes(), -1); | |||
ds.setValue("C", "C".getBytes(), -1); | |||
mds.commit(); | |||
byte[] va = mds.getValue("A"); | |||
byte[] va = ds.getValue("A"); | |||
assertNotNull(va); | |||
assertEquals("A", new String(va)); | |||
byte[] vc = mds.getValue("C"); | |||
VersioningKVEntry ventry = mds.getDataEntry("C"); | |||
byte[] vc = ds.getValue("C"); | |||
DataEntry<String, byte[]> ventry = ds.getDataEntry("C"); | |||
assertNotNull(vc); | |||
assertNotNull(ventry); | |||
assertEquals("C", new String(vc)); | |||
assertEquals("C", ventry.getKey().toUTF8String()); | |||
assertEquals("C", ventry.getKey()); | |||
HashDigest root1 = mds.getRootHash(); | |||
@@ -111,8 +114,8 @@ public class MerkleDataSetTest { | |||
int expStorageCount = 10; | |||
assertEquals(expStorageCount, storage.getStorageCount()); | |||
mds.setValue("B", "B".getBytes(), 0); | |||
mds.setValue("C", "C".getBytes(), 0); | |||
ds.setValue("B", "B".getBytes(), 0); | |||
ds.setValue("C", "C".getBytes(), 0); | |||
mds.commit(); | |||
HashDigest root2 = mds.getRootHash(); | |||
assertNotEquals(root1, root2); | |||
@@ -122,7 +125,7 @@ public class MerkleDataSetTest { | |||
expStorageCount = expStorageCount + 3; | |||
assertEquals(expStorageCount, storage.getStorageCount()); | |||
mds.setValue("D", "DValue".getBytes(), -1); | |||
ds.setValue("D", "DValue".getBytes(), -1); | |||
mds.commit(); | |||
HashDigest root3 = mds.getRootHash(); | |||
assertNotEquals(root2, root3); | |||
@@ -135,31 +138,31 @@ public class MerkleDataSetTest { | |||
assertEquals(expStorageCount, storage.getStorageCount()); | |||
// Check rollback function: Add some keys, and then rollback; | |||
long v = mds.setValue("E", "E-values".getBytes(), -1); | |||
long v = ds.setValue("E", "E-values".getBytes(), -1); | |||
assertEquals(v, 0); | |||
String expEValue = new String(mds.getValue("E")); | |||
String expEValue = new String(ds.getValue("E")); | |||
assertEquals(expEValue, "E-values"); | |||
v = mds.setValue("F", "F-values".getBytes(), -1); | |||
v = ds.setValue("F", "F-values".getBytes(), -1); | |||
assertEquals(v, 0); | |||
String expFValue = new String(mds.getValue("F")); | |||
String expFValue = new String(ds.getValue("F")); | |||
assertEquals(expFValue, "F-values"); | |||
v = mds.setValue("E", "E-values-1".getBytes(), 0); | |||
v = ds.setValue("E", "E-values-1".getBytes(), 0); | |||
assertEquals(v, 1); | |||
expEValue = new String(mds.getValue("E")); | |||
expEValue = new String(ds.getValue("E")); | |||
assertEquals(expEValue, "E-values-1"); | |||
mds.cancel(); | |||
byte[] bv = mds.getValue("E"); | |||
byte[] bv = ds.getValue("E"); | |||
assertNull(bv); | |||
bv = mds.getValue("F"); | |||
bv = ds.getValue("F"); | |||
assertNull(bv); | |||
v = mds.getVersion("E"); | |||
v = ds.getVersion("E"); | |||
assertEquals(-1, v); | |||
v = mds.getVersion("F"); | |||
v = ds.getVersion("F"); | |||
assertEquals(-1, v); | |||
// Expect that states has been recover; | |||
@@ -194,10 +197,11 @@ public class MerkleDataSetTest { | |||
MemoryKVStorage storage = new MemoryKVStorage(); | |||
MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); | |||
Dataset<String, byte[]> ds = DatasetHelper.map(mds); | |||
// 初始的时候没有任何数据,总是返回 null; | |||
VersioningKVEntry verKVEntry = mds.getDataEntry("NULL_KEY"); | |||
byte[] vbytes = mds.getValue("NULL_KEY"); | |||
DataEntry verKVEntry = ds.getDataEntry("NULL_KEY"); | |||
byte[] vbytes = ds.getValue("NULL_KEY"); | |||
assertNull(verKVEntry); | |||
assertNull(vbytes); | |||
@@ -217,7 +221,7 @@ public class MerkleDataSetTest { | |||
for (int i = 0; i < count; i++) { | |||
key = "data" + i; | |||
rand.nextBytes(data); | |||
v = mds.setValue(key, data, -1); | |||
v = ds.setValue(key, data, -1); | |||
dataVersions.put(key, v); | |||
dataValues.put(key + "_" + v, data); | |||
assertEquals(v, 0); | |||
@@ -237,7 +241,7 @@ public class MerkleDataSetTest { | |||
KeySnapshot ks = new KeySnapshot(); | |||
ks.proof = proof; | |||
ks.maxVersion = mds.getVersion(key); | |||
ks.maxVersion = ds.getVersion(key); | |||
snapshot.put(key, ks); | |||
} | |||
@@ -271,7 +275,7 @@ public class MerkleDataSetTest { | |||
key = "data" + i; | |||
rand.nextBytes(data); | |||
expVer = dataVersions.get(key); | |||
v = mds.setValue(key, data, expVer); | |||
v = ds.setValue(key, data, expVer); | |||
assertEquals(v, expVer + 1); | |||
@@ -300,7 +304,7 @@ public class MerkleDataSetTest { | |||
KeySnapshot ks = new KeySnapshot(); | |||
ks.proof = proof; | |||
ks.maxVersion = mds.getVersion(key); | |||
ks.maxVersion = ds.getVersion(key); | |||
snapshot.put(key, ks); | |||
} | |||
history.put(rootHash, snapshot); | |||
@@ -316,6 +320,7 @@ public class MerkleDataSetTest { | |||
MerkleDataSet mdsReload = new MerkleDataSet(hisRootHash, cryptoConfig, keyPrefix, storage, storage, | |||
true); | |||
Dataset<String, byte[]> dsReload = DatasetHelper.map(mdsReload); | |||
assertEquals(hisRootHash, mdsReload.getRootHash()); | |||
// verify every keys; | |||
@@ -323,7 +328,7 @@ public class MerkleDataSetTest { | |||
key = "data" + i; | |||
// 最新版本一致; | |||
long expLatestVersion = snapshot.get(key).maxVersion; | |||
long actualLatestVersion = mdsReload.getVersion(key); | |||
long actualLatestVersion = dsReload.getVersion(key); | |||
assertEquals(expLatestVersion, actualLatestVersion); | |||
// 数据证明一致; | |||
@@ -339,7 +344,7 @@ public class MerkleDataSetTest { | |||
for (long j = 0; j < actualLatestVersion; j++) { | |||
String keyver = key + "_" + j; | |||
byte[] expValue = dataValues.get(keyver); | |||
byte[] actualValue = mdsReload.getValue(key, j); | |||
byte[] actualValue = dsReload.getValue(key, j); | |||
assertTrue(BytesUtils.equals(expValue, actualValue)); | |||
} | |||
} | |||
@@ -365,10 +370,11 @@ public class MerkleDataSetTest { | |||
MemoryKVStorage storage = new MemoryKVStorage(); | |||
MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage); | |||
Dataset<String, byte[]> ds = DatasetHelper.map(mds); | |||
// 初始的时候没有任何数据,总是返回 null; | |||
VersioningKVEntry verKVEntry = mds.getDataEntry("NULL_KEY"); | |||
byte[] vbytes = mds.getValue("NULL_KEY"); | |||
DataEntry verKVEntry = ds.getDataEntry("NULL_KEY"); | |||
byte[] vbytes = ds.getValue("NULL_KEY"); | |||
assertNull(verKVEntry); | |||
assertNull(vbytes); | |||
@@ -388,7 +394,7 @@ public class MerkleDataSetTest { | |||
MerkleProof proof; | |||
for (int i = 0; i < count; i++) { | |||
key = "data" + i; | |||
v = mds.setValue(key, data, -1); | |||
v = ds.setValue(key, data, -1); | |||
dataVersions.put(key, v); | |||
// dataValues.put(key + "_" + v, data); | |||
assertEquals(v, 0); | |||
@@ -408,7 +414,7 @@ public class MerkleDataSetTest { | |||
KeySnapshot ks = new KeySnapshot(); | |||
ks.proof = proof; | |||
ks.maxVersion = mds.getVersion(key); | |||
ks.maxVersion = ds.getVersion(key); | |||
snapshot.put(key, ks); | |||
} | |||
@@ -418,6 +424,7 @@ public class MerkleDataSetTest { | |||
// verify; | |||
{ | |||
MerkleDataSet mdsReload = new MerkleDataSet(rootHash, cryptoConfig, keyPrefix, storage, storage, true); | |||
Dataset<String, byte[]> dsReload = DatasetHelper.map(mdsReload); | |||
// verify every keys; | |||
Map<String, KeySnapshot> snapshot = history.get(rootHash); | |||
MerkleProof expProof; | |||
@@ -429,7 +436,7 @@ public class MerkleDataSetTest { | |||
expProof = snapshot.get(key).proof; | |||
assertEquals(expProof.toString(), proof.toString()); | |||
byte[] value = mdsReload.getValue(key); | |||
byte[] value = dsReload.getValue(key); | |||
assertTrue(BytesUtils.equals(data, value)); | |||
} | |||
} | |||
@@ -332,24 +332,25 @@ public class TransactionBatchProcessorTest { | |||
newBlock = newBlockEditor.prepare(); | |||
newBlockEditor.commit(); | |||
BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", | |||
BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1", | |||
0); | |||
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", | |||
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1", | |||
1); | |||
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K2", | |||
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K2", | |||
0); | |||
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3", | |||
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K3", | |||
0); | |||
assertNotNull(v1_0); | |||
assertNotNull(v1_1); | |||
assertNotNull(v2); | |||
assertNotNull(v3); | |||
assertEquals("V-1-1", v1_0.getValue().toUTF8String()); | |||
assertEquals("V-1-2", v1_1.getValue().toUTF8String()); | |||
assertEquals("V-2-1", v2.getValue().toUTF8String()); | |||
assertEquals("V-3-1", v3.getValue().toUTF8String()); | |||
assertEquals("V-1-1", v1_0.getBytes().toUTF8String()); | |||
assertEquals("V-1-2", v1_1.getBytes().toUTF8String()); | |||
assertEquals("V-2-1", v2.getBytes().toUTF8String()); | |||
assertEquals("V-3-1", v3.getBytes().toUTF8String()); | |||
// 提交多笔数据写入的交易,包含存在数据版本冲突的交易,验证交易是否正确回滚; | |||
// 先写一笔正确的交易; k3 的版本将变为 1 ; | |||
@@ -376,22 +377,22 @@ public class TransactionBatchProcessorTest { | |||
newBlock = newBlockEditor.prepare(); | |||
newBlockEditor.commit(); | |||
BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1"); | |||
v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3"); | |||
BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K1"); | |||
v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getDataset().getValue("K3"); | |||
// k1 的版本仍然为1,没有更新; | |||
long k1_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) | |||
.getDataVersion("K1"); | |||
.getDataset().getVersion("K1"); | |||
assertEquals(1, k1_version); | |||
long k3_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) | |||
.getDataVersion("K3"); | |||
.getDataset().getVersion("K3"); | |||
assertEquals(1, k3_version); | |||
assertNotNull(v1); | |||
assertNotNull(v3); | |||
assertEquals("V-1-2", v1.getValue().toUTF8String()); | |||
assertEquals("V-3-2", v3.getValue().toUTF8String()); | |||
assertEquals("V-1-2", v1.getBytes().toUTF8String()); | |||
assertEquals("V-3-2", v3.getBytes().toUTF8String()); | |||
// // 验证正确性; | |||
// ledgerManager = new LedgerManager(); | |||
@@ -164,8 +164,8 @@ public class TransactionSetTest { | |||
for (int i = 0; i < acutualKVWriteSet.length; i++) { | |||
assertEquals(expKVWriteSet[i].getKey(), acutualKVWriteSet[i].getKey()); | |||
assertEquals(expKVWriteSet[i].getExpectedVersion(), acutualKVWriteSet[i].getExpectedVersion()); | |||
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), | |||
acutualKVWriteSet[i].getValue().getValue().toBytes())); | |||
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getBytes().toBytes(), | |||
acutualKVWriteSet[i].getValue().getBytes().toBytes())); | |||
} | |||
ContractCodeDeployOperation actualContractDplOp = (ContractCodeDeployOperation) actualOperations[3]; | |||
@@ -0,0 +1,11 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.utils.Dataset; | |||
public interface Account { | |||
BlockchainIdentity getID(); | |||
Dataset<String, TypedValue> getDataset(); | |||
} |
@@ -1,20 +1,20 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.utils.Bytes; | |||
@DataContract(code= DataCodes.ACCOUNT_HEADER) | |||
public interface AccountHeader extends MerkleSnapshot{ | |||
@DataField(order=1, primitiveType = PrimitiveType.BYTES) | |||
Bytes getAddress(); | |||
@DataField(order=2, primitiveType = PrimitiveType.BYTES) | |||
PubKey getPubKey(); | |||
} | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import com.jd.blockchain.binaryproto.DataContract; | |||
//import com.jd.blockchain.binaryproto.DataField; | |||
//import com.jd.blockchain.binaryproto.PrimitiveType; | |||
//import com.jd.blockchain.consts.DataCodes; | |||
//import com.jd.blockchain.crypto.PubKey; | |||
//import com.jd.blockchain.utils.Bytes; | |||
// | |||
//@Deprecated | |||
//@DataContract(code= DataCodes.ACCOUNT_HEADER) | |||
//public interface AccountHeader { //extends MerkleSnapshot{ | |||
// | |||
// @DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
// Bytes getAddress(); | |||
// | |||
// @DataField(order = 2, primitiveType=PrimitiveType.BYTES) | |||
// PubKey getPubKey(); | |||
// | |||
//} |
@@ -1,118 +0,0 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
/** | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BytesData implements BytesValue { | |||
DataType type; | |||
Bytes value; | |||
private BytesData(DataType type, byte[] bytes) { | |||
this.type = type; | |||
this.value = new Bytes(bytes); | |||
} | |||
private BytesData(DataType type, Bytes bytes) { | |||
this.type = type; | |||
this.value = bytes; | |||
} | |||
public static BytesValue fromType(DataType type, byte[] value) { | |||
return new BytesData(type, value); | |||
} | |||
public static BytesValue fromBytes(byte[] value) { | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromBytes(Bytes value) { | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromImage(byte[] value) { | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
public static BytesValue fromImage(Bytes value) { | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
/** | |||
* 以 UTF-8 编码从字符串转换为字节数组值; | |||
* | |||
* @param value | |||
* @return | |||
*/ | |||
public static BytesValue fromText(String value) { | |||
return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); | |||
} | |||
/** | |||
* 以 UTF-8 编码把字节数组值转换为字符串; | |||
* | |||
* @param bytesValue | |||
* @return | |||
*/ | |||
public static String toText(BytesValue bytesValue) { | |||
if (bytesValue == null) { | |||
return null; | |||
} | |||
if (bytesValue.getType() != DataType.TEXT) { | |||
throw new ValueTypeCastException("The expected value type is " + DataType.TEXT.toString() | |||
+ ", but it is actually " + bytesValue.getType().toString() + "!"); | |||
} | |||
return bytesValue.getValue().toUTF8String(); | |||
} | |||
public static BytesValue fromJSON(String value) { | |||
return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromXML(String value) { | |||
return new BytesData(DataType.XML, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt32(int value) { | |||
return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt64(long value) { | |||
return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt16(short value) { | |||
return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt8(byte value) { | |||
return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromTimestamp(long value) { | |||
return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromBoolean(boolean value) { | |||
return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
} | |||
@Override | |||
public DataType getType() { | |||
return this.type; | |||
} | |||
public void setType(DataType type) { | |||
this.type = type; | |||
} | |||
@Override | |||
public Bytes getValue() { | |||
return this.value; | |||
} | |||
} |
@@ -14,18 +14,18 @@ public class BytesDataList implements BytesValueList { | |||
} | |||
public static BytesValueList singleText(String value) { | |||
return new BytesDataList(BytesData.fromText(value)); | |||
return new BytesDataList(TypedValue.fromText(value)); | |||
} | |||
public static BytesValueList singleLong(long value) { | |||
return new BytesDataList(BytesData.fromInt64(value)); | |||
return new BytesDataList(TypedValue.fromInt64(value)); | |||
} | |||
public static BytesValueList singleInt(int value) { | |||
return new BytesDataList(BytesData.fromInt32(value)); | |||
return new BytesDataList(TypedValue.fromInt32(value)); | |||
} | |||
public static BytesValueList singleBoolean(boolean value) { | |||
return new BytesDataList(BytesData.fromBoolean(value)); | |||
return new BytesDataList(TypedValue.fromBoolean(value)); | |||
} | |||
} |
@@ -29,6 +29,6 @@ public interface BytesValue { | |||
* @return | |||
*/ | |||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
Bytes getValue(); | |||
Bytes getBytes(); | |||
} |
@@ -68,7 +68,7 @@ public class BytesValueEncoding { | |||
} | |||
// 将对象序列化 | |||
byte[] serialBytes = BinaryProtocol.encode(value, type); | |||
return BytesData.fromType(DataType.DATA_CONTRACT, serialBytes); | |||
return TypedValue.fromType(DataType.DATA_CONTRACT, serialBytes); | |||
} | |||
BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type); | |||
if (bytesValueResolver == null) { | |||
@@ -5,9 +5,10 @@ import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.CONTRACT) | |||
public interface ContractInfo extends AccountHeader { | |||
@DataContract(code= DataCodes.CONTRACT_ACCOUNT_HEADER) | |||
public interface ContractInfo extends BlockchainIdentity, MerkleSnapshot { | |||
@DataField(order=4, primitiveType= PrimitiveType.BYTES) | |||
byte[] getChainCode(); | |||
} |
@@ -106,6 +106,20 @@ public enum DataType { | |||
* DataContract 数据; | |||
*/ | |||
DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); | |||
public static final boolean BOOLEAN_DEFAULT_VALUE = false; | |||
public static final byte INT8_DEFAULT_VALUE = 0; | |||
public static final short INT16_DEFAULT_VALUE = 0; | |||
public static final int INT32_DEFAULT_VALUE = 0; | |||
public static final long INT64_DEFAULT_VALUE = 0; | |||
@EnumField(type = PrimitiveType.INT8) | |||
public final byte CODE; | |||
@@ -114,6 +128,51 @@ public enum DataType { | |||
this.CODE = code; | |||
} | |||
/** | |||
* 是否表示“文本类型”或“文本衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isText() { | |||
return BaseType.TEXT == (BaseType.TEXT & CODE); | |||
} | |||
/** | |||
* 是否表示“字节类型”或“字节衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBytes() { | |||
return BaseType.BYTES == (BaseType.BYTES & CODE); | |||
} | |||
/** | |||
* 是否表示“整数类型”或“整数衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isInteger() { | |||
return BaseType.INTEGER == (BaseType.INTEGER & CODE); | |||
} | |||
/** | |||
* 是否表示“布尔类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBoolean() { | |||
return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE); | |||
} | |||
/** | |||
* 是否表示“扩展类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isExt() { | |||
return BaseType.EXT == (BaseType.EXT & CODE); | |||
} | |||
public static DataType valueOf(byte code) { | |||
for (DataType dataType : DataType.values()) { | |||
if (dataType.CODE == code) { | |||
@@ -0,0 +1,44 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public interface HashProof { | |||
/** | |||
* 最大层级数; <br> | |||
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
* | |||
* @return | |||
* | |||
* @see MerkleTree#getLevel() | |||
*/ | |||
int getLevels(); | |||
/** | |||
* 返回证明中指定层级的节点的哈希; | |||
* <p> | |||
* | |||
* @param level | |||
* 参数值为 0 返回的是数据节点的哈希; <br> | |||
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
* @return | |||
*/ | |||
HashDigest getHash(int level); | |||
/** | |||
* 返回根节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getRootHash() { | |||
return getHash(getLevels()); | |||
} | |||
/** | |||
* 返回数据节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getDataHash() { | |||
return getHash(0); | |||
} | |||
} |
@@ -1,616 +0,0 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.math.BigInteger; | |||
import java.util.Date; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
/** | |||
* KV数据项; | |||
* | |||
* <p> | |||
* | |||
* {@link KVDataObject} 被设计为只读对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class KVDataObject implements KVDataEntry { | |||
private String key; | |||
private long version; | |||
private BytesValue bytesValue; | |||
public KVDataObject(String key, long version, BytesValue bytesValue) { | |||
this.key = key; | |||
this.version = version < 0 ? -1 : version; | |||
this.bytesValue = bytesValue; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getKey() | |||
*/ | |||
@Override | |||
public String getKey() { | |||
return key; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getVersion() | |||
*/ | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getType() | |||
*/ | |||
@Override | |||
public DataType getType() { | |||
return bytesValue == null ? DataType.NIL : bytesValue.getType(); | |||
} | |||
@Override | |||
public Object getValue() { | |||
if (bytesValue == null) { | |||
return null; | |||
} | |||
switch (getType()) { | |||
case NIL: | |||
return null; | |||
case TEXT: | |||
return bytesValue.getValue().toUTF8String(); | |||
case BYTES: | |||
return ByteArray.toHex(bytesValue.getValue().toBytes()); | |||
case INT64: | |||
return BytesUtils.toLong(bytesValue.getValue().toBytes()); | |||
case JSON: | |||
return bytesValue.getValue().toUTF8String(); | |||
case XML: | |||
return bytesValue.getValue().toUTF8String(); | |||
default: | |||
throw new IllegalStateException("Unsupported value type[" + getType() + "] to resolve!"); | |||
} | |||
} | |||
/** | |||
* 是否为空值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; | |||
* <p> | |||
* | |||
* @return | |||
*/ | |||
public boolean isNil() { | |||
return bytesValue == null || DataType.NIL == bytesValue.getType(); | |||
} | |||
/** | |||
* 字节数组形式的原始内容; | |||
* | |||
* @return | |||
*/ | |||
Bytes bytesArray() { | |||
return bytesValue.getValue(); | |||
} | |||
/** | |||
* 返回 8 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public byte tinyValue() { | |||
if (DataType.INT8 == getType()) { | |||
return bytesValue.getValue().toBytes()[0]; | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT8, getType())); | |||
} | |||
/** | |||
* 返回 16 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public short shortValue() { | |||
if (DataType.INT16 == getType()) { | |||
return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT16, getType())); | |||
} | |||
/** | |||
* 返回 32 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public int intValue() { | |||
if (DataType.INT32 == getType()) { | |||
return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT32, getType())); | |||
} | |||
/** | |||
* 返回 64 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public long longValue() { | |||
if (DataType.INT64 == getType()) { | |||
return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); | |||
} | |||
/** | |||
* 返回大整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public BigInteger bigIntValue() { | |||
if (DataType.BIG_INT == getType()) { | |||
return new BigInteger(bytesValue.getValue().toBytes()); | |||
} | |||
throw new IllegalStateException( | |||
String.format("Expected type [%s], but [%s]", DataType.BIG_INT, getType())); | |||
} | |||
/** | |||
* 返回布尔值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public boolean boolValue() { | |||
if (DataType.BOOLEAN == getType()) { | |||
return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); | |||
} | |||
throw new IllegalStateException( | |||
String.format("Expected type [%s], but [%s]", DataType.BOOLEAN, getType())); | |||
} | |||
/** | |||
* 返回日期时间值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public Date datetimeValue() { | |||
if (DataType.TIMESTAMP == getType()) { | |||
long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); | |||
return new Date(ts); | |||
} | |||
throw new IllegalStateException( | |||
String.format("Expected type [%s], but [%s]", DataType.TIMESTAMP, getType())); | |||
} | |||
/** | |||
* 返回大整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TEXT} / | |||
* {@link PrimitiveType#JSON} / {@link PrimitiveType#XML} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public String stringValue() { | |||
DataType type = getType(); | |||
if (DataType.TEXT == type || DataType.JSON == type || DataType.XML == type) { | |||
return bytesValue.getValue().toUTF8String(); | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s] or [%s] or [%s] , but [%s]", | |||
PrimitiveType.TEXT, DataType.JSON, DataType.XML, type)); | |||
} | |||
// // ---------------- | |||
// public KVDataEntry nextVersionNil() { | |||
// return nilState(key, version + 1); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionBoolean(boolean value) { | |||
// return booleanState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionTiny(byte value) { | |||
// return tinyState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionShort(short value) { | |||
// return shortState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionInt(int value) { | |||
// return intState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionLong(long value) { | |||
// return longState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionDatetime(Date value) { | |||
// return datetimeState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionJson(String value) { | |||
// return jsonState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionXml(String value) { | |||
// return xmlState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionBigInt(BigInteger value) { | |||
// return bigIntState(key, version + 1, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionText(boolean encrypted, String value) { | |||
// return textState(key, version + 1, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionBytes(boolean encrypted, byte[] value) { | |||
// return bytesState(key, version + 1, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionImage(boolean encrypted, byte[] value) { | |||
// return imageState(key, version + 1, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionVideo(boolean encrypted, byte[] value) { | |||
// return videoState(key, version + 1, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry nextVersionLocation(boolean encrypted, byte[] value) { | |||
// return locationState(key, version + 1, encrypted, value); | |||
// } | |||
// // ---------------- | |||
// | |||
// public KVDataEntry newNil() { | |||
// return nilState(key, version); | |||
// } | |||
// | |||
// public KVDataEntry newBoolean(boolean value) { | |||
// return booleanState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newTiny(byte value) { | |||
// return tinyState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newShort(short value) { | |||
// return shortState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newInt(int value) { | |||
// return intState(key, version, value); | |||
// } | |||
// | |||
// public KVDataObject newLong(long value) { | |||
// return longState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newDatetime(Date value) { | |||
// return datetimeState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newJson(String value) { | |||
// return jsonState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newXml(String value) { | |||
// return xmlState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newBigInt(BigInteger value) { | |||
// return bigIntState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newText(boolean encrypted, String value) { | |||
// return textState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newBytes(boolean encrypted, byte[] value) { | |||
// return bytesState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newImage(boolean encrypted, byte[] value) { | |||
// return imageState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newVideo(boolean encrypted, byte[] value) { | |||
// return videoState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newLocation(boolean encrypted, byte[] value) { | |||
// return locationState(key, version, encrypted, value); | |||
// } | |||
// | |||
// // ---------------- | |||
// | |||
// public KVDataEntry newNil(long version) { | |||
// return nilState(key, version); | |||
// } | |||
// | |||
// public KVDataEntry newBoolean(long version, boolean value) { | |||
// return booleanState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newTiny(long version, byte value) { | |||
// return tinyState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newShort(long version, short value) { | |||
// return shortState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newInt(long version, int value) { | |||
// return intState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newLong(long version, long value) { | |||
// return longState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newDatetime(long version, Date value) { | |||
// return datetimeState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newJson(long version, String value) { | |||
// return jsonState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newXml(long version, String value) { | |||
// return xmlState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newBigInt(long version, BigInteger value) { | |||
// return bigIntState(key, version, value); | |||
// } | |||
// | |||
// public KVDataEntry newText(long version, boolean encrypted, String value) { | |||
// return textState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newBytes(long version, boolean encrypted, byte[] value) { | |||
// return bytesState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newImage(long version, boolean encrypted, byte[] value) { | |||
// return imageState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newVideo(long version, boolean encrypted, byte[] value) { | |||
// return videoState(key, version, encrypted, value); | |||
// } | |||
// | |||
// public KVDataEntry newLocation(long version, boolean encrypted, byte[] value) { | |||
// return locationState(key, version, encrypted, value); | |||
// } | |||
// | |||
// // ---------------- | |||
// | |||
// public static KVDataEntry booleanState(String key, boolean value) { | |||
// return booleanState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry tinyState(String key, byte value) { | |||
// return tinyState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry shortState(String key, short value) { | |||
// return shortState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry intState(String key, int value) { | |||
// return intState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry longState(String key, long value) { | |||
// return longState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry datetimeState(String key, Date value) { | |||
// return datetimeState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry jsonState(String key, String value) { | |||
// return jsonState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry xmlState(String key, String value) { | |||
// return xmlState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataEntry bigIntState(String key, BigInteger value) { | |||
// return bigIntState(key, -1, value); | |||
// } | |||
// | |||
// public static KVDataObject textState(String key, String value) { | |||
// return textState(key, -1, false, value); | |||
// } | |||
// | |||
// public static KVDataEntry bytesState(String key, byte[] value) { | |||
// return bytesState(key, -1, false, value); | |||
// } | |||
// | |||
// public static KVDataEntry imageState(String key, byte[] value) { | |||
// return imageState(key, -1, false, value); | |||
// } | |||
// | |||
// public static KVDataEntry videoState(String key, byte[] value) { | |||
// return videoState(key, -1, false, value); | |||
// } | |||
// | |||
// public static KVDataEntry locationState(String key, byte[] value) { | |||
// return locationState(key, -1, false, value); | |||
// } | |||
// | |||
// // ---------------- | |||
// | |||
// public static KVDataEntry textState(String key, boolean encrypted, String value) { | |||
// return textState(key, -1, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry bytesState(String key, boolean encrypted, byte[] value) { | |||
// return bytesState(key, -1, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry imageState(String key, boolean encrypted, byte[] value) { | |||
// return imageState(key, -1, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry videoState(String key, boolean encrypted, byte[] value) { | |||
// return videoState(key, -1, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry locationState(String key, boolean encrypted, byte[] value) { | |||
// return locationState(key, -1, encrypted, value); | |||
// } | |||
// | |||
// // ---------------------- | |||
// | |||
// public static KVDataEntry nilState(String key) { | |||
// return new KVDataObject(key, ValueType.NIL, -1, false, BytesUtils.EMPTY_BYTES); | |||
// } | |||
// | |||
// public static KVDataEntry nilState(String key, long version) { | |||
// return new KVDataObject(key, ValueType.NIL, version, false, BytesUtils.EMPTY_BYTES); | |||
// } | |||
// | |||
// public static KVDataEntry booleanState(String key, long version, boolean value) { | |||
// byte[] v = { value ? (byte) 1 : (byte) 0 }; | |||
// return new KVDataObject(key, ValueType.BOOLEAN, version, false, v); | |||
// } | |||
// | |||
// public static KVDataEntry tinyState(String key, long version, byte value) { | |||
// byte[] v = { value }; | |||
// return new KVDataObject(key, ValueType.INT8, version, false, v); | |||
// } | |||
// | |||
// public static KVDataEntry shortState(String key, long version, short value) { | |||
// byte[] v = BytesUtils.toBytes(value); | |||
// return new KVDataObject(key, ValueType.INT16, version, false, v); | |||
// } | |||
// | |||
// public static KVDataEntry intState(String key, long version, int value) { | |||
// byte[] v = BytesUtils.toBytes(value); | |||
// return new KVDataObject(key, ValueType.INT32, version, false, v); | |||
// } | |||
// | |||
// public static KVDataObject longState(String key, long version, long value) { | |||
// byte[] v = BytesUtils.toBytes(value); | |||
// return new KVDataObject(key, ValueType.INT64, version, false, v); | |||
// } | |||
// | |||
// public static KVDataEntry datetimeState(String key, long version, Date value) { | |||
// byte[] v = BytesUtils.toBytes(value.getTime()); | |||
// return new KVDataObject(key, ValueType.DATETIME, version, false, v); | |||
// } | |||
// | |||
// public static KVDataObject textState(String key, long version, boolean encrypted, String value) { | |||
// try { | |||
// byte[] v = value.getBytes("UTF-8"); | |||
// return new KVDataObject(key, ValueType.TEXT, version, encrypted, v); | |||
// } catch (UnsupportedEncodingException e) { | |||
// throw new IllegalStateException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// public static KVDataEntry jsonState(String key, long version, String value) { | |||
// try { | |||
// byte[] v = value.getBytes("UTF-8"); | |||
// return new KVDataObject(key, ValueType.JSON, version, false, v); | |||
// } catch (UnsupportedEncodingException e) { | |||
// throw new IllegalStateException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// public static KVDataEntry xmlState(String key, long version, String value) { | |||
// try { | |||
// byte[] v = value.getBytes("UTF-8"); | |||
// return new KVDataObject(key, ValueType.XML, version, false, v); | |||
// } catch (UnsupportedEncodingException e) { | |||
// throw new IllegalStateException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// public static KVDataEntry bigIntState(String key, long version, BigInteger value) { | |||
// byte[] v = value.toByteArray(); | |||
// return new KVDataObject(key, ValueType.BIG_INT, version, false, v); | |||
// } | |||
// | |||
// public static KVDataEntry bytesState(String key, long version, boolean encrypted, byte[] value) { | |||
// return new KVDataObject(key, ValueType.BYTES, version, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry imageState(String key, long version, boolean encrypted, byte[] value) { | |||
// return new KVDataObject(key, ValueType.IMG, version, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry videoState(String key, long version, boolean encrypted, byte[] value) { | |||
// return new KVDataObject(key, ValueType.VIDEO, version, encrypted, value); | |||
// } | |||
// | |||
// public static KVDataEntry locationState(String key, long version, boolean encrypted, byte[] value) { | |||
// return new KVDataObject(key, ValueType.LOCATION, version, encrypted, value); | |||
// } | |||
} |
@@ -1,8 +1,6 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public interface MerkleProof { | |||
public interface MerkleProof extends HashProof { | |||
/** | |||
* 所证明的数据节点的序列号; | |||
@@ -11,62 +9,46 @@ public interface MerkleProof { | |||
*/ | |||
long getSN(); | |||
/** | |||
* 最大层级数; <br> | |||
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
* | |||
* @return | |||
* | |||
* @see MerkleTree#getLevel() | |||
*/ | |||
int getLevels(); | |||
/** | |||
* 返回证明中指定层级的节点的哈希; | |||
* <p> | |||
* | |||
* @param level | |||
* 参数值为 0 返回的是数据节点的哈希; <br> | |||
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
* @return | |||
*/ | |||
HashDigest getHash(int level); | |||
MerkleNode getNode(int level); | |||
// /** | |||
// * 返回证明中指定层级的数据起始序号; | |||
// * 最大层级数; <br> | |||
// * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
// * | |||
// * @param level | |||
// * @return | |||
// * | |||
// * @see MerkleTree#getLevel() | |||
// */ | |||
// long getStartingSN(int level); | |||
// int getLevels(); | |||
// | |||
// /** | |||
// * 返回证明中指定层级的数据记录总数; | |||
// * 返回证明中指定层级的节点的哈希; | |||
// * <p> | |||
// * | |||
// * @param level | |||
// * 参数值为 0 返回的是数据节点的哈希; <br> | |||
// * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
// * @return | |||
// */ | |||
// long getDataCount(int level); | |||
// HashDigest getHash(int level); | |||
/** | |||
* 返回根节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getRootHash() { | |||
return getHash(getLevels()); | |||
} | |||
MerkleNode getNode(int level); | |||
/** | |||
* 返回数据节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getDataHash() { | |||
return getHash(0); | |||
} | |||
// * 返回根节点的哈希; | |||
// * | |||
// * @return | |||
// */ | |||
// default HashDigest getRootHash() { | |||
// return getHash(getLevels()); | |||
// } | |||
// | |||
// /** | |||
// * 返回数据节点的哈希; | |||
// * | |||
// * @return | |||
// */ | |||
// default HashDigest getDataHash() { | |||
// return getHash(0); | |||
// } | |||
default MerkleDataNode getDataNode() { | |||
return (MerkleDataNode)getNode(0); | |||
@@ -0,0 +1,78 @@ | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 强类型的“键-值”数据对象; | |||
* | |||
* <p> | |||
* | |||
* {@link TypedKVData} 被设计为只读对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TypedKVData implements TypedKVEntry { | |||
private String key; | |||
private long version; | |||
private DataType type; | |||
private Object value; | |||
public TypedKVData(String key, long version, DataType type, Object value) { | |||
this.key = key; | |||
this.version = version; | |||
this.type = type; | |||
this.value = value; | |||
} | |||
public TypedKVData(String key, long version, BytesValue bytesValue) { | |||
this.key = key; | |||
this.version = version; | |||
TypedValue typedValue; | |||
if (bytesValue != null && bytesValue instanceof TypedValue) { | |||
typedValue = (TypedValue) bytesValue; | |||
} else { | |||
typedValue = TypedValue.wrap(bytesValue); | |||
} | |||
this.type = typedValue.getType(); | |||
this.value = typedValue.getValue(); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getKey() | |||
*/ | |||
@Override | |||
public String getKey() { | |||
return key; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getVersion() | |||
*/ | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.KVDataEntry#getType() | |||
*/ | |||
@Override | |||
public DataType getType() { | |||
return type; | |||
} | |||
@Override | |||
public Object getValue() { | |||
return value; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger; | |||
public interface KVDataEntry { | |||
public interface TypedKVEntry { | |||
/** | |||
* 键名; | |||
@@ -33,4 +33,12 @@ public interface KVDataEntry { | |||
*/ | |||
Object getValue(); | |||
default long longValue() { | |||
if (getType() == DataType.INT64) { | |||
Object value = getValue(); | |||
return value == null ? 0 : (long) value; | |||
} | |||
throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); | |||
} | |||
} |
@@ -0,0 +1,454 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.math.BigInteger; | |||
import java.util.Date; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
/** | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TypedValue implements BytesValue { | |||
public static final BytesValue NIL = new TypedValue(); | |||
private DataType type; | |||
private Bytes value; | |||
private TypedValue(DataType type, byte[] bytes) { | |||
this.type = type; | |||
this.value = new Bytes(bytes); | |||
} | |||
private TypedValue(DataType type, Bytes bytes) { | |||
this.type = type; | |||
this.value = bytes; | |||
} | |||
private TypedValue(BytesValue bytesValue) { | |||
if (bytesValue == null) { | |||
this.type = DataType.NIL; | |||
} else { | |||
this.type = bytesValue.getType(); | |||
this.value = bytesValue.getBytes(); | |||
} | |||
} | |||
private TypedValue() { | |||
this.type = DataType.NIL; | |||
} | |||
@Override | |||
public DataType getType() { | |||
return this.type; | |||
} | |||
@Override | |||
public Bytes getBytes() { | |||
return this.value; | |||
} | |||
public Object getValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
switch (type) { | |||
case BOOLEAN: | |||
return toBoolean(); | |||
case INT8: | |||
return toInt8(); | |||
case INT16: | |||
return toInt16(); | |||
case INT32: | |||
return toInt32(); | |||
case INT64: | |||
return toInt64(); | |||
case BIG_INT: | |||
return toBigInteger(); | |||
case TIMESTAMP: | |||
return toDatetime(); | |||
case TEXT: | |||
case JSON: | |||
case XML: | |||
return toText(); | |||
case BYTES: | |||
case VIDEO: | |||
case IMG: | |||
case LOCATION: | |||
case ENCRYPTED_DATA: | |||
return toBytesArray(); | |||
case HASH_DIGEST: | |||
return toHashDegist(); | |||
case PUB_KEY: | |||
return toPubKey(); | |||
case SIGNATURE_DIGEST: | |||
return toSignatureDigest(); | |||
case DATA_CONTRACT: | |||
return toBytesArray(); | |||
default: | |||
throw new IllegalStateException(String.format("Type [%s] has not be supported!", type)); | |||
} | |||
} | |||
/** | |||
* 是否为空值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; | |||
* <p> | |||
* | |||
* @return | |||
*/ | |||
public boolean isNil() { | |||
return value == null || DataType.NIL == type; | |||
} | |||
/** | |||
* 返回 8 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public byte tinyValue() { | |||
if (isNil()) { | |||
return DataType.INT8_DEFAULT_VALUE; | |||
} | |||
if (DataType.INT8 == getType()) { | |||
return toInt8(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", type)); | |||
} | |||
private byte toInt8() { | |||
return value.toBytes()[0]; | |||
} | |||
/** | |||
* 返回 16 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public short shortValue() { | |||
if (isNil()) { | |||
return DataType.INT16_DEFAULT_VALUE; | |||
} | |||
if (DataType.INT16 == getType()) { | |||
return toInt16(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", type)); | |||
} | |||
private short toInt16() { | |||
return BytesUtils.toShort(value.toBytes(), 0); | |||
} | |||
/** | |||
* 返回 32 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public int intValue() { | |||
if (isNil()) { | |||
return DataType.INT32_DEFAULT_VALUE; | |||
} | |||
if (DataType.INT32 == getType()) { | |||
return toInt32(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", type)); | |||
} | |||
private int toInt32() { | |||
return BytesUtils.toInt(value.toBytes(), 0); | |||
} | |||
/** | |||
* 返回 64 位整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public long longValue() { | |||
if (isNil()) { | |||
return DataType.INT64_DEFAULT_VALUE; | |||
} | |||
if (DataType.INT64 == type) { | |||
return toInt64(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", type)); | |||
} | |||
private long toInt64() { | |||
return BytesUtils.toLong(value.toBytes(), 0); | |||
} | |||
/** | |||
* 返回大整数值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public BigInteger bigIntValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (DataType.BIG_INT == type) { | |||
return toBigInteger(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to BigInteger!", type)); | |||
} | |||
private BigInteger toBigInteger() { | |||
return new BigInteger(value.toBytes()); | |||
} | |||
/** | |||
* 返回布尔值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public boolean boolValue() { | |||
if (isNil()) { | |||
return DataType.BOOLEAN_DEFAULT_VALUE; | |||
} | |||
if (DataType.BOOLEAN == type) { | |||
return toBoolean(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", type)); | |||
} | |||
private boolean toBoolean() { | |||
return BytesUtils.toBoolean(value.toBytes()[0]); | |||
} | |||
/** | |||
* 返回日期时间值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public Date datetimeValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (DataType.TIMESTAMP == type) { | |||
return toDatetime(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to datetime!", type)); | |||
} | |||
private Date toDatetime() { | |||
long ts = BytesUtils.toLong(value.toBytes()); | |||
return new Date(ts); | |||
} | |||
/** | |||
* 返回文本值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public String stringValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (type.isText()) { | |||
return toText(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type)); | |||
} | |||
private String toText() { | |||
return value.toUTF8String(); | |||
} | |||
/** | |||
* 返回字节数组的值; | |||
* <p> | |||
* | |||
* 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效; | |||
* <p> | |||
* | |||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||
* | |||
* @return | |||
*/ | |||
public byte[] bytesValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (type.isBytes()) { | |||
return toBytesArray(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type)); | |||
} | |||
private byte[] toBytesArray() { | |||
return value.toBytes(); | |||
} | |||
public HashDigest hashDigestValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (DataType.HASH_DIGEST == type) { | |||
return toHashDegist(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to hash digest!", type)); | |||
} | |||
private HashDigest toHashDegist() { | |||
return new HashDigest(toBytesArray()); | |||
} | |||
public PubKey pubKeyValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (DataType.PUB_KEY == type) { | |||
return toPubKey(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", type)); | |||
} | |||
private PubKey toPubKey() { | |||
return new PubKey(toBytesArray()); | |||
} | |||
public SignatureDigest signatureDigestValue() { | |||
if (isNil()) { | |||
return null; | |||
} | |||
if (DataType.SIGNATURE_DIGEST == type) { | |||
return toSignatureDigest(); | |||
} | |||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to signature digest!", type)); | |||
} | |||
private SignatureDigest toSignatureDigest() { | |||
return new SignatureDigest(toBytesArray()); | |||
} | |||
public static TypedValue wrap(BytesValue value) { | |||
return new TypedValue(value); | |||
} | |||
public static TypedValue fromType(DataType type, byte[] value) { | |||
return new TypedValue(type, value); | |||
} | |||
public static TypedValue fromBytes(byte[] value) { | |||
return new TypedValue(DataType.BYTES, value); | |||
} | |||
public static TypedValue fromBytes(Bytes value) { | |||
return new TypedValue(DataType.BYTES, value); | |||
} | |||
public static TypedValue fromImage(byte[] value) { | |||
return new TypedValue(DataType.IMG, value); | |||
} | |||
public static TypedValue fromImage(Bytes value) { | |||
return new TypedValue(DataType.IMG, value); | |||
} | |||
/** | |||
* 以 UTF-8 编码从字符串转换为字节数组值; | |||
* | |||
* @param value | |||
* @return | |||
*/ | |||
public static TypedValue fromText(String value) { | |||
return new TypedValue(DataType.TEXT, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromJSON(String value) { | |||
return new TypedValue(DataType.JSON, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromXML(String value) { | |||
return new TypedValue(DataType.XML, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromInt32(int value) { | |||
return new TypedValue(DataType.INT32, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromInt64(long value) { | |||
return new TypedValue(DataType.INT64, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromInt16(short value) { | |||
return new TypedValue(DataType.INT16, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromInt8(byte value) { | |||
return new TypedValue(DataType.INT8, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromTimestamp(long value) { | |||
return new TypedValue(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromBoolean(boolean value) { | |||
return new TypedValue(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
} | |||
public static TypedValue fromPubKey(PubKey pubKey) { | |||
return new TypedValue(DataType.PUB_KEY, pubKey.toBytes()); | |||
} | |||
} |
@@ -0,0 +1,472 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import java.math.BigInteger; | |||
//import java.util.Date; | |||
// | |||
//import com.jd.blockchain.binaryproto.PrimitiveType; | |||
//import com.jd.blockchain.crypto.HashDigest; | |||
//import com.jd.blockchain.crypto.PubKey; | |||
//import com.jd.blockchain.crypto.SignatureDigest; | |||
//import com.jd.blockchain.utils.Bytes; | |||
//import com.jd.blockchain.utils.io.BytesUtils; | |||
// | |||
//public class TypedValue_ { | |||
// | |||
// private BytesValue bytesValue; | |||
// | |||
// public TypedValue_(BytesValue bytesValue) { | |||
// this.bytesValue = bytesValue; | |||
// } | |||
// | |||
// public DataType getType() { | |||
// return bytesValue == null ? DataType.NIL : bytesValue.getType(); | |||
// } | |||
// | |||
// public Object getValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// switch (bytesValue.getType()) { | |||
// case BOOLEAN: | |||
// return toBoolean(); | |||
// case INT8: | |||
// return toInt8(); | |||
// case INT16: | |||
// return toInt16(); | |||
// case INT32: | |||
// return toInt32(); | |||
// case INT64: | |||
// return toInt64(); | |||
// case BIG_INT: | |||
// return toBigInteger(); | |||
// case TIMESTAMP: | |||
// return toDatetime(); | |||
// case TEXT: | |||
// case JSON: | |||
// case XML: | |||
// return toText(); | |||
// | |||
// case BYTES: | |||
// case VIDEO: | |||
// case IMG: | |||
// case LOCATION: | |||
// case ENCRYPTED_DATA: | |||
// return toBytesArray(); | |||
// | |||
// case HASH_DIGEST: | |||
// return toHashDegist(); | |||
// case PUB_KEY: | |||
// return toPubKey(); | |||
// case SIGNATURE_DIGEST: | |||
// return toSignatureDigest(); | |||
// | |||
// case DATA_CONTRACT: | |||
// return toBytesArray(); | |||
// default: | |||
// throw new IllegalStateException(String.format("Type [%s] has not be supported!", bytesValue.getType())); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * 是否为空值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; | |||
// * <p> | |||
// * | |||
// * @return | |||
// */ | |||
// public boolean isNil() { | |||
// return bytesValue == null || DataType.NIL == bytesValue.getType(); | |||
// } | |||
// | |||
// /** | |||
// * 返回 8 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public byte tinyValue() { | |||
// if (isNil()) { | |||
// return DataType.INT8_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT8 == getType()) { | |||
// return toInt8(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", bytesValue.getType())); | |||
// } | |||
// | |||
// private byte toInt8() { | |||
// return bytesValue.getValue().toBytes()[0]; | |||
// } | |||
// | |||
// /** | |||
// * 返回 16 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public short shortValue() { | |||
// if (isNil()) { | |||
// return DataType.INT16_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT16 == getType()) { | |||
// return toInt16(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", bytesValue.getType())); | |||
// } | |||
// | |||
// private short toInt16() { | |||
// return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回 32 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public int intValue() { | |||
// if (isNil()) { | |||
// return DataType.INT32_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT32 == getType()) { | |||
// return toInt32(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", bytesValue.getType())); | |||
// } | |||
// | |||
// private int toInt32() { | |||
// return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回 64 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public long longValue() { | |||
// if (isNil()) { | |||
// return DataType.INT64_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT64 == bytesValue.getType()) { | |||
// return toInt64(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", bytesValue.getType())); | |||
// | |||
// } | |||
// | |||
// private long toInt64() { | |||
// return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回大整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public BigInteger bigIntValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.BIG_INT == bytesValue.getType()) { | |||
// return toBigInteger(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to BigInteger!", bytesValue.getType())); | |||
// } | |||
// | |||
// private BigInteger toBigInteger() { | |||
// return new BigInteger(bytesValue.getValue().toBytes()); | |||
// } | |||
// | |||
// /** | |||
// * 返回布尔值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public boolean boolValue() { | |||
// if (isNil()) { | |||
// return DataType.BOOLEAN_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.BOOLEAN == bytesValue.getType()) { | |||
// return toBoolean(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", bytesValue.getType())); | |||
// } | |||
// | |||
// private boolean toBoolean() { | |||
// return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); | |||
// } | |||
// | |||
// /** | |||
// * 返回日期时间值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public Date datetimeValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.TIMESTAMP == bytesValue.getType()) { | |||
// return toDatetime(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to datetime!", bytesValue.getType())); | |||
// } | |||
// | |||
// private Date toDatetime() { | |||
// long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); | |||
// return new Date(ts); | |||
// } | |||
// | |||
// /** | |||
// * 返回文本值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public String stringValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// DataType type = bytesValue.getType(); | |||
// if (type.isText()) { | |||
// return toText(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type)); | |||
// } | |||
// | |||
// private String toText() { | |||
// return bytesValue.getValue().toUTF8String(); | |||
// } | |||
// | |||
// /** | |||
// * 返回字节数组的值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public byte[] bytesValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// DataType type = bytesValue.getType(); | |||
// if (type.isBytes()) { | |||
// return toBytesArray(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type)); | |||
// } | |||
// | |||
// private byte[] toBytesArray() { | |||
// return bytesValue.getValue().toBytes(); | |||
// } | |||
// | |||
// public HashDigest hashDigestValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.HASH_DIGEST == bytesValue.getType()) { | |||
// return toHashDegist(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to hash digest!", bytesValue.getType())); | |||
// } | |||
// | |||
// private HashDigest toHashDegist() { | |||
// return new HashDigest(toBytesArray()); | |||
// } | |||
// | |||
// public PubKey pubKeyValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.PUB_KEY == bytesValue.getType()) { | |||
// return toPubKey(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", bytesValue.getType())); | |||
// } | |||
// | |||
// private PubKey toPubKey() { | |||
// return new PubKey(toBytesArray()); | |||
// } | |||
// | |||
// public SignatureDigest signatureDigestValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.SIGNATURE_DIGEST == bytesValue.getType()) { | |||
// return toSignatureDigest(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to signature digest!", bytesValue.getType())); | |||
// } | |||
// | |||
// private SignatureDigest toSignatureDigest() { | |||
// return new SignatureDigest(toBytesArray()); | |||
// } | |||
// | |||
// public BytesValue convertToBytesValue() { | |||
// return bytesValue == null ? TypedBytesValue.NIL : bytesValue; | |||
// } | |||
// | |||
// public static TypedBytesValue fromText(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromText(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBoolean(String key, boolean value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt8(String key, byte value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt8(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt16(String key, short value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt16(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt32(String key, int value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt32(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt64(String key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt64(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBytes(String key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromTimestamp(String key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromJSON(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromJSON(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromXML(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromXML(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromImage(String key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromImage(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromText(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromText(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBoolean(Bytes key, boolean value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt8(Bytes key, byte value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt8(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt16(Bytes key, short value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt16(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt32(Bytes key, int value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt32(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt64(Bytes key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt64(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBytes(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromTimestamp(Bytes key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromJSON(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromJSON(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromXML(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromXML(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromImage(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromImage(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
//} |
@@ -0,0 +1,12 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.PubKey; | |||
@DataContract(code= DataCodes.USER_ACCOUNT_HEADER) | |||
public interface UserAccountHeader extends BlockchainIdentity { | |||
PubKey getDataPubKey(); | |||
} |
@@ -2,11 +2,8 @@ package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.PubKey; | |||
@DataContract(code= DataCodes.USER) | |||
public interface UserInfo extends AccountHeader { | |||
PubKey getDataPubKey(); | |||
@DataContract(code = DataCodes.USER_INFO) | |||
public interface UserInfo extends UserAccountHeader { | |||
} |
@@ -47,7 +47,7 @@ public abstract class AbstractBytesValueResolver implements BytesValueResolver { | |||
if (!isSupport(dataType)) { | |||
throw new IllegalStateException(String.format("Un-support encode DataType[%s] Object !!!", dataType.name())); | |||
} | |||
return decode(value.getValue()); | |||
return decode(value.getBytes()); | |||
} | |||
protected abstract Object decode(Bytes value); |
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -21,7 +21,7 @@ public class BooleanToBytesValueResolver extends AbstractBytesValueResolver { | |||
if (!isSupport(type)) { | |||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
} | |||
return BytesData.fromBoolean((boolean) value); | |||
return TypedValue.fromBoolean((boolean) value); | |||
} | |||
@Override | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -21,9 +21,9 @@ public class BytesToBytesValueResolver extends AbstractBytesValueResolver { | |||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
} | |||
if (type.equals(byte[].class)) { | |||
return BytesData.fromBytes((byte[]) value); | |||
return TypedValue.fromBytes((byte[]) value); | |||
} | |||
return BytesData.fromBytes((Bytes) value); | |||
return TypedValue.fromBytes((Bytes) value); | |||
} | |||
@Override | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -21,7 +21,7 @@ public class IntegerToBytesValueResolver extends AbstractBytesValueResolver { | |||
if (!isSupport(type)) { | |||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
} | |||
return BytesData.fromInt32((int) value); | |||
return TypedValue.fromInt32((int) value); | |||
} | |||
@Override | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -21,7 +21,7 @@ public class LongToBytesValueResolver extends AbstractBytesValueResolver { | |||
if (!isSupport(type)) { | |||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
} | |||
return BytesData.fromInt64((long)value); | |||
return TypedValue.fromInt64((long)value); | |||
} | |||
@Override | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -21,7 +21,7 @@ public class ShortToBytesValueResolver extends AbstractBytesValueResolver { | |||
if (!isSupport(type)) { | |||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
} | |||
return BytesData.fromInt16((short)value); | |||
return TypedValue.fromInt16((short)value); | |||
} | |||
@Override | |||
@@ -1,6 +1,6 @@ | |||
package com.jd.blockchain.ledger.resolver; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataType; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -26,10 +26,10 @@ public class StringToBytesValueResolver extends AbstractBytesValueResolver { | |||
// 类型判断 | |||
String valString = (String)value; | |||
if (JSONSerializeUtils.isJSON(valString)) { | |||
return BytesData.fromJSON(valString); | |||
return TypedValue.fromJSON(valString); | |||
} | |||
// 暂不处理XML格式 | |||
return BytesData.fromText(valString); | |||
return TypedValue.fromText(valString); | |||
} | |||
@Override | |||
@@ -3,9 +3,9 @@ package com.jd.blockchain.transaction; | |||
import org.springframework.cglib.core.Block; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
@@ -250,7 +250,7 @@ public interface BlockchainQueryService { | |||
* @param address | |||
* @return | |||
*/ | |||
AccountHeader getDataAccount(HashDigest ledgerHash, String address); | |||
BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户中指定的键的最新值; <br> | |||
@@ -264,9 +264,9 @@ public interface BlockchainQueryService { | |||
* @param keys | |||
* @return | |||
*/ | |||
KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); | |||
KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); | |||
/** | |||
* 返回指定数据账户中KV数据的总数; <br> | |||
@@ -287,7 +287,7 @@ public interface BlockchainQueryService { | |||
* 如果参数值为 -1,则返回全部的记录;<br> | |||
* @return | |||
*/ | |||
KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||
/** | |||
* 返回合约账户信息; | |||
@@ -306,7 +306,7 @@ public interface BlockchainQueryService { | |||
* @param count | |||
* @return | |||
*/ | |||
AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count); | |||
BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get data accounts by ledgerHash and its range; | |||
@@ -316,7 +316,7 @@ public interface BlockchainQueryService { | |||
* @param count | |||
* @return | |||
*/ | |||
AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get contract accounts by ledgerHash and its range; | |||
@@ -326,5 +326,5 @@ public interface BlockchainQueryService { | |||
* @param count | |||
* @return | |||
*/ | |||
AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
} |
@@ -1,7 +1,7 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromImage(value); | |||
BytesValue bytesValue = TypedValue.fromImage(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
BytesValue bytesValue = TypedValue.fromText(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromInt64(value); | |||
BytesValue bytesValue = TypedValue.fromInt64(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromJSON(value); | |||
BytesValue bytesValue = TypedValue.fromJSON(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromXML(value); | |||
BytesValue bytesValue = TypedValue.fromXML(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
BytesValue bytesValue = TypedValue.fromTimestamp(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@@ -26,7 +26,7 @@ public class BytesToBytesValueResolverTest { | |||
assertEquals(bytesValue.getType(), DataType.BYTES); | |||
assertEquals(bytesObj, bytesValue.getValue()); | |||
assertEquals(bytesObj, bytesValue.getBytes()); | |||
Bytes resolveBytesObj = (Bytes)resolver.decode(bytesValue); | |||
@@ -28,9 +28,9 @@ public class BytesValueEncodingTest { | |||
BytesValue longBytesVal2 = BytesValueEncoding.encodeSingle(longVal, long.class); | |||
BytesValue longBytesVal3 = BytesValueEncoding.encodeSingle(longVal, Long.class); | |||
assertEquals(longBytesVal1.getValue(), longBytesVal2.getValue()); | |||
assertEquals(longBytesVal1.getBytes(), longBytesVal2.getBytes()); | |||
assertEquals(longBytesVal1.getType(), longBytesVal2.getType()); | |||
assertEquals(longBytesVal2.getValue(), longBytesVal3.getValue()); | |||
assertEquals(longBytesVal2.getBytes(), longBytesVal3.getBytes()); | |||
assertEquals(longBytesVal2.getType(), longBytesVal3.getType()); | |||
long resolveLongVal1 = (long)BytesValueEncoding.decode(longBytesVal1); | |||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.BytesDataList; | |||
import com.jd.blockchain.ledger.BytesValueList; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
@@ -41,7 +41,7 @@ public class ContractEventSendOpTemplateTest { | |||
DataContractRegistry.register(ContractEventSendOperation.class); | |||
DataContractRegistry.register(Operation.class); | |||
String contractAddress = "zhangsan-address", event = "zhangsan-event"; | |||
BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args")); | |||
BytesValueList args = new BytesDataList(TypedValue.fromText("zhangsan-args")); | |||
data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); | |||
} | |||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
@@ -41,11 +41,11 @@ public class DataAccountKVSetOpTemplateTest { | |||
String accountAddress = "zhangsandhakhdkah"; | |||
data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); | |||
KVData kvData1 = | |||
new KVData("test1", BytesData.fromText("zhangsan"), 9999L); | |||
new KVData("test1", TypedValue.fromText("zhangsan"), 9999L); | |||
KVData kvData2 = | |||
new KVData("test2", BytesData.fromText("lisi"), 9990L); | |||
new KVData("test2", TypedValue.fromText("lisi"), 9990L); | |||
KVData kvData3 = | |||
new KVData("test3", BytesData.fromText("wangwu"), 1990L); | |||
new KVData("test3", TypedValue.fromText("wangwu"), 1990L); | |||
data.set(kvData1); | |||
data.set(kvData2); | |||
data.set(kvData3); | |||
@@ -63,7 +63,7 @@ public class DataAccountKVSetOpTemplateTest { | |||
assertEquals(dataKv.length, resolvedKv.length); | |||
for (int i = 0; i < dataKv.length; i++) { | |||
assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); | |||
assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), resolvedKv[i].getValue().getValue().toBytes()); | |||
assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), resolvedKv[i].getValue().getBytes().toBytes()); | |||
assertEquals(dataKv[i].getValue().getType().CODE, resolvedKv[i].getValue().getType().CODE); | |||
assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); | |||
@@ -22,13 +22,13 @@ public class IntegerToBytesValueResolverTest { | |||
BytesValue intBytesValue2 = resolver.encode(intVal, Integer.class); | |||
assertEquals(intBytesValue.getValue(), intBytesValue1.getValue()); | |||
assertEquals(intBytesValue.getBytes(), intBytesValue1.getBytes()); | |||
assertEquals(intBytesValue.getValue(), intBytesValue2.getValue()); | |||
assertEquals(intBytesValue.getBytes(), intBytesValue2.getBytes()); | |||
Bytes intBytes = Bytes.fromInt(intVal); | |||
assertEquals(intBytes, intBytesValue.getValue()); | |||
assertEquals(intBytes, intBytesValue.getBytes()); | |||
assertEquals(intBytesValue.getType(), DataType.INT32); | |||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
import com.jd.blockchain.transaction.KVData; | |||
@@ -38,7 +38,7 @@ public class KVDataTest { | |||
byte[] value = "test-value".getBytes(); | |||
long expectedVersion = 9999L; | |||
kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); | |||
kvData = new KVData(key, TypedValue.fromBytes(value), expectedVersion); | |||
} | |||
@Test | |||
@@ -48,7 +48,7 @@ public class KVDataTest { | |||
System.out.println("------Assert start ------"); | |||
assertEquals(resolvedKvData.getKey(), kvData.getKey()); | |||
assertEquals(resolvedKvData.getExpectedVersion(), kvData.getExpectedVersion()); | |||
assertArrayEquals(resolvedKvData.getValue().getValue().toBytes(), kvData.getValue().getValue().toBytes()); | |||
assertArrayEquals(resolvedKvData.getValue().getBytes().toBytes(), kvData.getValue().getBytes().toBytes()); | |||
System.out.println("------Assert OK ------"); | |||
} | |||
} |
@@ -23,13 +23,13 @@ public class LongToBytesValueResolverTest { | |||
BytesValue longBytesValue2 = resolver.encode(longVal, Long.class); | |||
assertEquals(longBytesValue.getValue(), longBytesValue1.getValue()); | |||
assertEquals(longBytesValue.getBytes(), longBytesValue1.getBytes()); | |||
assertEquals(longBytesValue.getValue(), longBytesValue2.getValue()); | |||
assertEquals(longBytesValue.getBytes(), longBytesValue2.getBytes()); | |||
Bytes longBytes = Bytes.fromLong(longVal); | |||
assertEquals(longBytes, longBytesValue.getValue()); | |||
assertEquals(longBytes, longBytesValue.getBytes()); | |||
assertEquals(longBytesValue.getType(), DataType.INT64); | |||
@@ -21,7 +21,7 @@ public class ShortToBytesValueResolverTest { | |||
Bytes shortBytes = new Bytes(BytesUtils.toBytes(shortVal)); | |||
assertEquals(shortBytes, shortBytesValue.getValue()); | |||
assertEquals(shortBytes, shortBytesValue.getBytes()); | |||
assertEquals(shortBytesValue.getType(), DataType.INT16); | |||
@@ -20,7 +20,7 @@ public class StringToBytesValueResolverTest { | |||
BytesValue textBytesValue = resolver.encode(textVal); | |||
assertEquals(Bytes.fromString(textVal), textBytesValue.getValue()); | |||
assertEquals(Bytes.fromString(textVal), textBytesValue.getBytes()); | |||
assertEquals(textBytesValue.getType(), DataType.TEXT); | |||
@@ -43,7 +43,7 @@ public class StringToBytesValueResolverTest { | |||
Person person = new Person("zhangsan", 80); | |||
String personJson = JSON.toJSONString(person); | |||
BytesValue textBytesValue = resolver.encode(personJson); | |||
assertEquals(Bytes.fromString(personJson), textBytesValue.getValue()); | |||
assertEquals(Bytes.fromString(personJson), textBytesValue.getBytes()); | |||
assertEquals(textBytesValue.getType(), DataType.JSON); | |||
} | |||
@@ -77,8 +77,8 @@ public class TxContentBlobTest { | |||
for (int j = 0; j < dataKv.length; j++) { | |||
assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); | |||
assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); | |||
assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), | |||
resolvedKv[i].getValue().getValue().toBytes()); | |||
assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), | |||
resolvedKv[i].getValue().getBytes().toBytes()); | |||
} | |||
} | |||
} | |||
@@ -108,8 +108,8 @@ public class TxContentBlobTest { | |||
for (int j = 0; j < dataKv.length; j++) { | |||
assertEquals(dataKv[i].getKey(), resolvedKv[i].getKey()); | |||
assertEquals(dataKv[i].getExpectedVersion(), resolvedKv[i].getExpectedVersion()); | |||
assertArrayEquals(dataKv[i].getValue().getValue().toBytes(), | |||
resolvedKv[i].getValue().getValue().toBytes()); | |||
assertArrayEquals(dataKv[i].getValue().getBytes().toBytes(), | |||
resolvedKv[i].getValue().getBytes().toBytes()); | |||
} | |||
} | |||
} | |||
@@ -3,7 +3,6 @@ package com.jd.blockchain.peer.web; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.ledger.*; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.web.bind.annotation.PathVariable; | |||
import org.springframework.web.bind.annotation.RequestBody; | |||
@@ -14,6 +13,22 @@ import org.springframework.web.bind.annotation.RestController; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
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.TypedKVData; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.ledger.core.ContractAccountQuery; | |||
import com.jd.blockchain.ledger.core.DataAccount; | |||
import com.jd.blockchain.ledger.core.DataAccountQuery; | |||
@@ -23,7 +38,10 @@ import com.jd.blockchain.ledger.core.ParticipantCertData; | |||
import com.jd.blockchain.ledger.core.TransactionQuery; | |||
import com.jd.blockchain.ledger.core.UserAccountQuery; | |||
import com.jd.blockchain.transaction.BlockchainQueryService; | |||
import com.jd.blockchain.utils.ArrayUtils; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.DataIterator; | |||
import com.jd.blockchain.utils.QueryUtil; | |||
@RestController | |||
@@ -72,7 +90,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
} | |||
return null; | |||
} | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/admininfo") | |||
@Override | |||
public LedgerAdminInfo getLedgerAdminInfo(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | |||
@@ -326,18 +344,18 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") | |||
@Override | |||
public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
return dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
return dataAccountSet.getAccount(Bytes.fromBase58(address)).getID(); | |||
} | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { | |||
if (keys == null || keys.length == 0) { | |||
return null; | |||
@@ -347,15 +365,15 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
long ver; | |||
for (int i = 0; i < entries.length; i++) { | |||
ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
ver = dataAccount.getDataset().getVersion(keys[i]); | |||
if (ver < 0) { | |||
entries[i] = new KVDataObject(keys[i], -1, null); | |||
entries[i] = new TypedKVData(keys[i], -1, null); | |||
} else { | |||
BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); | |||
entries[i] = new KVDataObject(keys[i], ver, value); | |||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | |||
entries[i] = new TypedKVData(keys[i], ver, value); | |||
} | |||
} | |||
@@ -365,7 +383,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address, @RequestBody KVInfoVO kvInfoVO) { | |||
// parse kvInfoVO; | |||
List<String> keyList = new ArrayList<>(); | |||
@@ -396,21 +414,21 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
long ver = -1; | |||
for (int i = 0; i < entries.length; i++) { | |||
// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
ver = versions[i]; | |||
if (ver < 0) { | |||
entries[i] = new KVDataObject(keys[i], -1, null); | |||
entries[i] = new TypedKVData(keys[i], -1, null); | |||
} else { | |||
if (dataAccount.getDataEntriesTotalCount() == 0 | |||
|| dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null) { | |||
if (dataAccount.getDataset().getDataCount() == 0 | |||
|| dataAccount.getDataset().getValue(keys[i], ver) == null) { | |||
// is the address is not exist; the result is null; | |||
entries[i] = new KVDataObject(keys[i], -1, null); | |||
entries[i] = new TypedKVData(keys[i], -1, null); | |||
} else { | |||
BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); | |||
entries[i] = new KVDataObject(keys[i], ver, value); | |||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | |||
entries[i] = new TypedKVData(keys[i], ver, value); | |||
} | |||
} | |||
} | |||
@@ -421,7 +439,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
@RequestMapping(method = { RequestMethod.GET, | |||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
@Override | |||
public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
@@ -431,27 +449,33 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); | |||
return dataAccount.getDataEntries(pages[0], pages[1]); | |||
// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); | |||
// return dataAccount.getDataEntries(pages[0], pages[1]); | |||
DataIterator<String, TypedValue> iterator = dataAccount.getDataset().iterator(); | |||
iterator.skip(fromIndex); | |||
DataEntry<String, TypedValue>[] dataEntries = iterator.next(count); | |||
TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, | |||
e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); | |||
return typedKVEntries; | |||
} | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") | |||
@Override | |||
public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
return dataAccount.getDataEntriesTotalCount(); | |||
return dataAccount.getDataset().getDataCount(); | |||
} | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") | |||
@Override | |||
public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathVariable(name = "address") String address) { | |||
@PathVariable(name = "address") String address) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
LedgerBlock block = ledger.getLatestBlock(); | |||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
@@ -468,7 +492,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
*/ | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") | |||
@Override | |||
public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
@@ -488,7 +512,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
*/ | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") | |||
@Override | |||
public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
@@ -500,7 +524,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") | |||
@Override | |||
public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
public BlockchainIdentity[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | |||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | |||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | |||
@@ -39,14 +39,14 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
public class ClientResolveUtil { | |||
public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||
public static TypedKVEntry[] read(TypedKVEntry[] kvDataEntries) { | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
return kvDataEntries; | |||
} | |||
KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||
TypedKVEntry[] resolveKvDataEntries = new TypedKVEntry[kvDataEntries.length]; | |||
// kvDataEntries是代理对象,需要处理 | |||
for (int i = 0; i < kvDataEntries.length; i++) { | |||
KVDataEntry kvDataEntry = kvDataEntries[i]; | |||
TypedKVEntry kvDataEntry = kvDataEntries[i]; | |||
String key = kvDataEntry.getKey(); | |||
long version = kvDataEntry.getVersion(); | |||
DataType dataType = kvDataEntry.getType(); | |||
@@ -108,7 +108,7 @@ public class ClientResolveUtil { | |||
public static Object readValueByBytesValue(BytesValue bytesValue) { | |||
DataType dataType = bytesValue.getType(); | |||
Bytes saveVal = bytesValue.getValue(); | |||
Bytes saveVal = bytesValue.getBytes(); | |||
Object showVal; | |||
switch (dataType) { | |||
case BYTES: | |||
@@ -151,7 +151,7 @@ public class ClientResolveUtil { | |||
String realValBase58 = valueObj.getJSONObject("value").getString("value"); | |||
String key = currWriteSetObj.getString("key"); | |||
DataType dataType = DataType.valueOf(typeStr); | |||
BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
BytesValue bytesValue = TypedValue.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||
kvOperation.set(kvData); | |||
} | |||
@@ -200,7 +200,7 @@ public class ClientResolveUtil { | |||
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||
String pubKeyBase58 = pubKeyObj.getString("value"); | |||
// 生成ParticipantNode对象 | |||
ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||
ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()), null); | |||
participantNodes[i] = participantCertData; | |||
} | |||
ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||
@@ -294,11 +294,12 @@ public class ClientResolveUtil { | |||
this.pubKey = participantNode.getPubKey(); | |||
} | |||
public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey) { | |||
public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { | |||
this.id = id; | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
this.participantNodeState = participantNodeState; | |||
} | |||
@@ -329,7 +330,7 @@ public class ClientResolveUtil { | |||
} | |||
public static class KvData implements KVDataEntry { | |||
public static class KvData implements TypedKVEntry { | |||
private String key; | |||
@@ -1,9 +1,9 @@ | |||
package com.jd.blockchain.sdk.proxy; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
@@ -156,25 +156,25 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||
} | |||
@Override | |||
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { | |||
public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { | |||
return getQueryService(ledgerHash).getDataAccount(ledgerHash, address); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); | |||
return ClientResolveUtil.read(kvDataEntries); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); | |||
return ClientResolveUtil.read(kvDataEntries); | |||
} | |||
@Override | |||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); | |||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); | |||
return ClientResolveUtil.read(kvDataEntries); | |||
} | |||
@@ -189,17 +189,17 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||
} | |||
@Override | |||
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
return getQueryService(ledgerHash).getUsers(ledgerHash, fromIndex, count); | |||
} | |||
@Override | |||
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
return getQueryService(ledgerHash).getDataAccounts(ledgerHash, fromIndex, count); | |||
} | |||
@Override | |||
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
return getQueryService(ledgerHash).getContractAccounts(ledgerHash, fromIndex, count); | |||
} | |||
} |
@@ -487,7 +487,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method=HttpMethod.GET, path="ledgers/{ledgerHash}/accounts/address/{address}") | |||
@Override | |||
AccountHeader getDataAccount(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
BlockchainIdentity getDataAccount(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@PathParam(name="address") String address); | |||
/** | |||
@@ -504,13 +504,13 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries") | |||
@Override | |||
KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@PathParam(name="address") String address, | |||
@RequestParam(name="keys", array = true) String... keys); | |||
@HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") | |||
@Override | |||
KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@PathParam(name="address") String address, | |||
@RequestBody KVInfoVO kvInfoVO); | |||
@@ -531,7 +531,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | |||
@Override | |||
KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, | |||
TypedKVEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, | |||
@PathParam(name = "address") String address, | |||
@RequestParam(name = "fromIndex", required = false) int fromIndex, | |||
@RequestParam(name = "count", required = false) int count); | |||
@@ -569,7 +569,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/users") | |||
@Override | |||
AccountHeader[] getUsers(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
BlockchainIdentity[] getUsers(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@RequestParam(name="fromIndex", required = false) int fromIndex, | |||
@RequestParam(name="count", required = false) int count); | |||
@@ -582,7 +582,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/accounts") | |||
@Override | |||
AccountHeader[] getDataAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
BlockchainIdentity[] getDataAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@RequestParam(name="fromIndex", required = false) int fromIndex, | |||
@RequestParam(name="count", required = false) int count); | |||
@@ -595,7 +595,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||
*/ | |||
@HttpAction(method = HttpMethod.GET, path = "ledgers/{ledgerHash}/contracts") | |||
@Override | |||
AccountHeader[] getContractAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
BlockchainIdentity[] getContractAccounts(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, | |||
@RequestParam(name="fromIndex", required = false) int fromIndex, | |||
@RequestParam(name="count", required = false) int count); | |||
@@ -9,8 +9,8 @@ import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.KVDataObject; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.TypedKVData; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
@@ -47,16 +47,16 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { | |||
} | |||
// 查询当前值; | |||
KVDataEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, | |||
TypedKVEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, | |||
assetHolderAddress); | |||
// 计算资产的发行总数; | |||
KVDataObject currTotal = (KVDataObject) kvEntries[0]; | |||
TypedKVData currTotal = (TypedKVData) kvEntries[0]; | |||
long newTotal = currTotal.longValue() + amount; | |||
eventContext.getLedger().dataAccount(ASSET_ADDRESS).setInt64(KEY_TOTAL, newTotal, currTotal.getVersion()); | |||
// 分配到持有者账户; | |||
KVDataObject holderAmount = (KVDataObject) kvEntries[1]; | |||
TypedKVData holderAmount = (TypedKVData) kvEntries[1]; | |||
long newHodlerAmount = holderAmount.longValue() + amount; | |||
eventContext.getLedger().dataAccount(ASSET_ADDRESS) | |||
.setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) | |||
@@ -77,10 +77,10 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { | |||
checkSignerPermission(fromAddress); | |||
// 查询现有的余额; | |||
KVDataEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, | |||
TypedKVEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, | |||
fromAddress, toAddress); | |||
KVDataEntry fromBalanceKV = origBalances[0]; | |||
KVDataEntry toBalanceKV = origBalances[1]; | |||
TypedKVEntry fromBalanceKV = origBalances[0]; | |||
TypedKVEntry toBalanceKV = origBalances[1]; | |||
long fromBalance = fromBalanceKV.getVersion() == -1 ? 0 : (long) fromBalanceKV.getValue(); | |||
long toBalance = toBalanceKV.getVersion() == -1 ? 0 : (long) toBalanceKV.getValue(); | |||
@@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.Transaction; | |||
@@ -67,7 +67,7 @@ public class SDKDemo_Query { | |||
// 获取数据; | |||
String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | |||
String[] objKeys = new String[] { "x001", "x002" }; | |||
KVDataEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); | |||
TypedKVEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); | |||
long payloadVersion = kvData[0].getVersion(); | |||
@@ -6,7 +6,7 @@ import static com.jd.blockchain.transaction.ContractReturnValue.decode; | |||
import com.jd.blockchain.contract.TransferContract; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
@@ -106,11 +106,11 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
} | |||
private long readByKvOperation(String address, String account) { | |||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); | |||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | |||
} | |||
KVDataEntry kvDataEntry = kvDataEntries[0]; | |||
TypedKVEntry kvDataEntry = kvDataEntries[0]; | |||
if (kvDataEntry.getVersion() == -1) { | |||
return 0L; | |||
} | |||
@@ -79,11 +79,11 @@ public class SDK_Contract_Random_Demo extends SDK_Base_Demo { | |||
} | |||
private long readByKvOperation(String address, String account) { | |||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); | |||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | |||
} | |||
KVDataEntry kvDataEntry = kvDataEntries[0]; | |||
TypedKVEntry kvDataEntry = kvDataEntries[0]; | |||
if (kvDataEntry.getVersion() == -1) { | |||
return 0L; | |||
} | |||
@@ -107,9 +107,9 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { | |||
// KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); | |||
// 获取数据账户下所有的KV列表 | |||
KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); | |||
TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); | |||
if (kvData != null && kvData.length > 0) { | |||
for (KVDataEntry kvDatum : kvData) { | |||
for (TypedKVEntry kvDatum : kvData) { | |||
System.out.println("kvData.key=" + kvDatum.getKey()); | |||
System.out.println("kvData.version=" + kvDatum.getVersion()); | |||
System.out.println("kvData.type=" + kvDatum.getType()); | |||
@@ -19,12 +19,12 @@ import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
import com.jd.blockchain.crypto.SignatureFunction; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.EndpointRequest; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
@@ -98,7 +98,7 @@ public class SDK_GateWay_Query_Test_ { | |||
System.out.println("contractCount=" + count); | |||
count = service.getContractCount(ledgerHash, hashDigest); | |||
System.out.println("contractCount=" + count); | |||
AccountHeader contract = service.getContract(ledgerHash, "12345678"); | |||
BlockchainIdentity contract = service.getContract(ledgerHash, "12345678"); | |||
System.out.println(contract); | |||
LedgerBlock block = service.getBlock(ledgerHash, hashDigest); | |||
@@ -109,7 +109,7 @@ public class SDK_GateWay_Query_Test_ { | |||
count = service.getDataAccountCount(ledgerHash, hashDigest); | |||
System.out.println("dataAccountCount=" + count); | |||
AccountHeader dataAccount = service.getDataAccount(ledgerHash, "1245633"); | |||
BlockchainIdentity dataAccount = service.getDataAccount(ledgerHash, "1245633"); | |||
System.out.println(dataAccount.getAddress()); | |||
count = service.getTransactionCount(ledgerHash, hashDigest); | |||
@@ -149,8 +149,8 @@ public class SDK_GateWay_Query_Test_ { | |||
String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | |||
String[] objKeys = new String[] { "x001", "x002" }; | |||
KVDataEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); | |||
for (KVDataEntry kvDatum : kvData) { | |||
TypedKVEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); | |||
for (TypedKVEntry kvDatum : kvData) { | |||
System.out.println("kvData.key=" + kvDatum.getKey()); | |||
System.out.println("kvData.version=" + kvDatum.getVersion()); | |||
System.out.println("kvData.value=" + kvDatum.getValue()); | |||
@@ -1,8 +1,8 @@ | |||
package com.jd.blockchain.storage.service.impl.redis; | |||
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.DataEntry; | |||
import redis.clients.jedis.Jedis; | |||
import redis.clients.jedis.JedisPool; | |||
@@ -45,7 +45,7 @@ public class RedisVerioningStorage implements VersioningKVStorage { | |||
} | |||
@Override | |||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||
public DataEntry getEntry(Bytes key, long version) { | |||
byte[] value = get(key, version); | |||
if (value == null) { | |||
return null; | |||
@@ -101,7 +101,7 @@ public class RedisVerioningStorage implements VersioningKVStorage { | |||
} | |||
private static class VersioningKVData implements VersioningKVEntry{ | |||
private static class VersioningKVData implements DataEntry{ | |||
private Bytes key; | |||
@@ -7,9 +7,9 @@ import java.util.concurrent.locks.ReentrantLock; | |||
import org.apache.commons.collections4.map.LRUMap; | |||
import org.rocksdb.*; | |||
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.DataEntry; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
/** | |||
@@ -127,7 +127,7 @@ public class RocksDBVersioningStorage implements VersioningKVStorage { | |||
} | |||
@Override | |||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||
public DataEntry getEntry(Bytes key, long version) { | |||
byte[] value = get(key, version); | |||
if (value == null) { | |||
return null; | |||
@@ -226,7 +226,7 @@ public class RocksDBVersioningStorage implements VersioningKVStorage { | |||
} | |||
} | |||
private static class VersioningKVData implements VersioningKVEntry { | |||
private static class VersioningKVData implements DataEntry { | |||
private Bytes key; | |||
@@ -1,20 +0,0 @@ | |||
package com.jd.blockchain.storage.service; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 版本化的键值数据项; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface VersioningKVEntry { | |||
// String getKey(); | |||
Bytes getKey(); | |||
long getVersion(); | |||
byte[] getValue(); | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.jd.blockchain.storage.service; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
/** | |||
* Versioning Key-Value Storage | |||
@@ -40,7 +41,7 @@ public interface VersioningKVStorage extends BatchStorageService { | |||
* @param version | |||
* @return | |||
*/ | |||
VersioningKVEntry getEntry(Bytes key, long version); | |||
DataEntry<Bytes, byte[]> getEntry(Bytes key, long version); | |||
/** | |||
* Return the specified verson's value; <br> | |||
@@ -7,10 +7,10 @@ import java.util.concurrent.ForkJoinTask; | |||
import java.util.concurrent.RecursiveTask; | |||
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; | |||
import com.jd.blockchain.utils.DataEntry; | |||
/** | |||
* {@link BufferedKVStorage} 缓冲写入的KV存储;<br> | |||
@@ -77,9 +77,9 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage | |||
} | |||
return ws.getLatestVersion(); | |||
} | |||
@Override | |||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||
public DataEntry<Bytes, byte[]> getEntry(Bytes key, long version) { | |||
VersioningWritingSet ws = versioningCache.get(key); | |||
if (ws == null) { | |||
return origVersioningStorage.getEntry(key, version); | |||
@@ -484,7 +484,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage | |||
return startingVersion; | |||
} | |||
public VersioningKVEntry getEntry(long version) { | |||
public DataEntry<Bytes, byte[]> getEntry(long version) { | |||
byte[] value = get(version); | |||
if (value == null) { | |||
return null; | |||
@@ -505,7 +505,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage | |||
} | |||
} | |||
private static class VersioningKVData implements VersioningKVEntry { | |||
private static class VersioningKVData implements DataEntry<Bytes, byte[]> { | |||
private Bytes key; | |||
@@ -5,9 +5,9 @@ import java.util.Set; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.KVStorageService; | |||
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.DataEntry; | |||
import com.jd.blockchain.utils.io.BytesMap; | |||
public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap<Bytes> { | |||
@@ -21,7 +21,7 @@ public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, | |||
} | |||
@Override | |||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||
public DataEntry getEntry(Bytes key, long version) { | |||
return verStorage.getEntry(key, version); | |||
} | |||
@@ -1,24 +1,23 @@ | |||
package com.jd.blockchain.storage.service.utils; | |||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
public class VersioningKVData implements VersioningKVEntry { | |||
public class VersioningKVData<K, V> implements DataEntry<K, V> { | |||
private Bytes key; | |||
private K key; | |||
private long version; | |||
private byte[] value; | |||
private V value; | |||
public VersioningKVData(Bytes key, long version, byte[] value) { | |||
public VersioningKVData(K key, long version, V value) { | |||
this.key = key; | |||
this.version = version; | |||
this.value = value; | |||
} | |||
@Override | |||
public Bytes getKey() { | |||
public K getKey() { | |||
return key; | |||
} | |||
@@ -28,7 +27,7 @@ public class VersioningKVData implements VersioningKVEntry { | |||
} | |||
@Override | |||
public byte[] getValue() { | |||
public V getValue() { | |||
return value; | |||
} | |||
@@ -5,9 +5,9 @@ import java.util.Map; | |||
import java.util.Set; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
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.DataEntry; | |||
import com.jd.blockchain.utils.io.BytesMap; | |||
public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap<Bytes> { | |||
@@ -42,7 +42,7 @@ public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap<Byt | |||
} | |||
@Override | |||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||
public DataEntry getEntry(Bytes key, long version) { | |||
VersioningWritingSet ws = versioningCache.get(key); | |||
if (ws == null) { | |||
return null; | |||
@@ -195,7 +195,7 @@ public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap<Byt | |||
return startingVersion; | |||
} | |||
public VersioningKVEntry getEntry(long version) { | |||
public DataEntry getEntry(long version) { | |||
byte[] value = get(version); | |||
if (value == null) { | |||
return null; | |||
@@ -21,12 +21,12 @@ import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerInitProperties; | |||
@@ -216,8 +216,8 @@ public class IntegrationTest { | |||
ledgerOfNode0.retrieveLatestBlock(); // 更新内存 | |||
// 先验证应答 | |||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); | |||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); | |||
for (TypedKVEntry kvDataEntry : kvDataEntries) { | |||
String valHexText = (String) kvDataEntry.getValue(); | |||
byte[] valBytes = HexUtils.decode(valHexText); | |||
String valText = new String(valBytes); | |||
@@ -420,7 +420,7 @@ public class IntegrationTest { | |||
UserInfo userInfo = blockchainService.getUser(ledgerHash, userAddress.toString()); | |||
// getDataAccount | |||
AccountHeader accountHeader = blockchainService.getDataAccount(ledgerHash, dataAddress.toString()); | |||
BlockchainIdentity accountHeader = blockchainService.getDataAccount(ledgerHash, dataAddress.toString()); | |||
// getDataEntries | |||
@@ -660,9 +660,9 @@ public class IntegrationTest { | |||
LedgerQuery ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); | |||
LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight()); | |||
BytesValue val1InDb = ledgerOfNode0.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) | |||
.getBytes("A"); | |||
.getDataset().getValue("A"); | |||
BytesValue val2InDb = ledgerOfNode0.getDataAccountSet(block).getAccount(contractDataKey.getAddress()) | |||
.getBytes(KEY_TOTAL); | |||
.getDataset().getValue(KEY_TOTAL); | |||
} | |||
/** | |||