@@ -1,7 +1,7 @@ | |||||
package com.jd.blockchain.contract; | package com.jd.blockchain.contract; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.TypedKVEntry; | |||||
@Contract | @Contract | ||||
public class ReadContractImpl implements EventProcessingAware, ReadContract { | public class ReadContractImpl implements EventProcessingAware, ReadContract { | ||||
@@ -24,7 +24,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||||
@Override | @Override | ||||
@ContractEvent(name = "read-key") | @ContractEvent(name = "read-key") | ||||
public String read(String address, String 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) { | if (kvDataEntries != null && kvDataEntries.length == 1) { | ||||
return kvDataEntries[0].getValue().toString(); | return kvDataEntries[0].getValue().toString(); | ||||
@@ -35,7 +35,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||||
@Override | @Override | ||||
@ContractEvent(name = "version-key") | @ContractEvent(name = "version-key") | ||||
public Long readVersion(String address, String 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) { | if (kvDataEntries != null && kvDataEntries.length == 1) { | ||||
return kvDataEntries[0].getVersion(); | return kvDataEntries[0].getVersion(); | ||||
@@ -2,7 +2,7 @@ package com.jd.blockchain.contract; | |||||
import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||
import com.jd.blockchain.crypto.HashDigest; | 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.KVDataVO; | ||||
import com.jd.blockchain.ledger.KVInfoVO; | import com.jd.blockchain.ledger.KVInfoVO; | ||||
@@ -14,7 +14,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||||
@Override | @Override | ||||
public String create(String address, String account, long money) { | 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 | // 肯定有返回值,但若不存在则返回version=-1 | ||||
if (kvDataEntries != null && kvDataEntries.length > 0) { | if (kvDataEntries != null && kvDataEntries.length > 0) { | ||||
long currVersion = kvDataEntries[0].getVersion(); | long currVersion = kvDataEntries[0].getVersion(); | ||||
@@ -32,13 +32,13 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||||
@Override | @Override | ||||
public String transfer(String address, String from, String to, long money) { | 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) { | if (kvDataEntries == null || kvDataEntries.length != 2) { | ||||
throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | ||||
} else { | } else { | ||||
// 判断from账号中钱数量是否足够 | // 判断from账号中钱数量是否足够 | ||||
long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | ||||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||||
for (TypedKVEntry kvDataEntry : kvDataEntries) { | |||||
if (kvDataEntry.getKey().equals(from)) { | if (kvDataEntry.getKey().equals(from)) { | ||||
fromMoney = (long) kvDataEntry.getValue(); | fromMoney = (long) kvDataEntry.getValue(); | ||||
fromVersion = kvDataEntry.getVersion(); | fromVersion = kvDataEntry.getVersion(); | ||||
@@ -62,7 +62,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||||
@Override | @Override | ||||
public long read(String address, String account) { | 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) { | if (kvDataEntries == null || kvDataEntries.length == 0) { | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -71,7 +71,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||||
@Override | @Override | ||||
public String readAll(String address, String account) { | 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) { | if (kvDataEntries == null || kvDataEntries.length == 0) { | ||||
return ""; | return ""; | ||||
@@ -91,7 +91,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr | |||||
KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); | 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); | return JSON.toJSONString(allEntries); | ||||
} | } | ||||
@@ -25,7 +25,7 @@ import com.jd.blockchain.gateway.PeerService; | |||||
import com.jd.blockchain.gateway.service.DataRetrievalService; | import com.jd.blockchain.gateway.service.DataRetrievalService; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.ContractInfo; | 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.KVInfoVO; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | import com.jd.blockchain.ledger.LedgerAdminInfo; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
@@ -261,7 +261,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
@PathVariable("address") String address, @RequestParam("keys") String... keys) { | @PathVariable("address") String address, @RequestParam("keys") String... keys) { | ||||
return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); | return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); | ||||
} | } | ||||
@@ -269,7 +269,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
@PathVariable("address") String address, @RequestBody KVInfoVO kvInfoVO) { | @PathVariable("address") String address, @RequestBody KVInfoVO kvInfoVO) { | ||||
return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); | return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); | ||||
} | } | ||||
@@ -277,7 +277,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, | |||||
@PathVariable("address") String address, | @PathVariable("address") String address, | ||||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | ||||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | ||||
@@ -2,8 +2,8 @@ package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
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.ledger.MerkleProof; | import com.jd.blockchain.ledger.MerkleProof; | ||||
import com.jd.blockchain.ledger.TypedValue; | import com.jd.blockchain.ledger.TypedValue; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -8,8 +8,9 @@ import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.ContractInfo; | 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.KVDataVO; | ||||
import com.jd.blockchain.ledger.KVInfoVO; | import com.jd.blockchain.ledger.KVInfoVO; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | import com.jd.blockchain.ledger.LedgerAdminInfo; | ||||
@@ -22,12 +23,15 @@ import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.TransactionState; | import com.jd.blockchain.ledger.TransactionState; | ||||
import com.jd.blockchain.ledger.UserInfo; | import com.jd.blockchain.ledger.UserInfo; | ||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.utils.ArrayUtils; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.DataEntry; | |||||
import com.jd.blockchain.utils.DataIterator; | |||||
import com.jd.blockchain.utils.QueryUtil; | import com.jd.blockchain.utils.QueryUtil; | ||||
public class LedgerQueryService implements BlockchainQueryService { | 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 HashDigest[] ledgerHashs; | ||||
@@ -278,7 +282,7 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
} | } | ||||
@Override | @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) { | if (keys == null || keys.length == 0) { | ||||
return EMPTY_ENTRIES; | return EMPTY_ENTRIES; | ||||
} | } | ||||
@@ -287,7 +291,8 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||||
long ver; | long ver; | ||||
for (int i = 0; i < entries.length; i++) { | for (int i = 0; i < entries.length; i++) { | ||||
final String currKey = keys[i]; | final String currKey = keys[i]; | ||||
@@ -295,17 +300,17 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); | ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); | ||||
if (ver < 0) { | if (ver < 0) { | ||||
entries[i] = new KVDataObject(currKey, -1, null); | |||||
entries[i] = new TypedKVData(currKey, -1, null); | |||||
} else { | } else { | ||||
BytesValue value = dataAccount.getDataset().getValue(currKey, ver); | BytesValue value = dataAccount.getDataset().getValue(currKey, ver); | ||||
entries[i] = new KVDataObject(currKey, ver, value); | |||||
entries[i] = new TypedKVData(currKey, ver, value); | |||||
} | } | ||||
} | } | ||||
return entries; | return entries; | ||||
} | } | ||||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||||
public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||||
// parse kvInfoVO; | // parse kvInfoVO; | ||||
List<String> keyList = new ArrayList<>(); | List<String> keyList = new ArrayList<>(); | ||||
List<Long> versionList = new ArrayList<>(); | List<Long> versionList = new ArrayList<>(); | ||||
@@ -335,22 +340,22 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||||
long ver = -1; | long ver = -1; | ||||
for (int i = 0; i < entries.length; i++) { | for (int i = 0; i < entries.length; i++) { | ||||
// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | ||||
// dataAccount.getBytes(Bytes.fromString(keys[i]),1); | // dataAccount.getBytes(Bytes.fromString(keys[i]),1); | ||||
ver = versions[i]; | ver = versions[i]; | ||||
if (ver < 0) { | if (ver < 0) { | ||||
entries[i] = new KVDataObject(keys[i], -1, null); | |||||
entries[i] = new TypedKVData(keys[i], -1, null); | |||||
} else { | } else { | ||||
if (dataAccount.getDataset().getDataCount() == 0 | if (dataAccount.getDataset().getDataCount() == 0 | ||||
|| dataAccount.getDataset().getValue(keys[i], ver) == null) { | || dataAccount.getDataset().getValue(keys[i], ver) == null) { | ||||
// is the address is not exist; the result is 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 { | } else { | ||||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | ||||
entries[i] = new KVDataObject(keys[i], ver, value); | |||||
entries[i] = new TypedKVData(keys[i], ver, value); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -359,14 +364,22 @@ public class LedgerQueryService implements BlockchainQueryService { | |||||
} | } | ||||
@Override | @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); | checkLedgerHash(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); | |||||
return dataAccount.getDataset()..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 | @Override | ||||
@@ -136,7 +136,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
* @return | * @return | ||||
*/ | */ | ||||
public boolean contains(Bytes address) { | 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; | return latestVersion > -1; | ||||
} | } | ||||
@@ -10,10 +10,12 @@ import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | ||||
import com.jd.blockchain.storage.service.utils.VersioningKVData; | 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.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | |||||
import com.jd.blockchain.utils.DataEntry; | import com.jd.blockchain.utils.DataEntry; | ||||
import com.jd.blockchain.utils.DataIterator; | |||||
import com.jd.blockchain.utils.Dataset; | import com.jd.blockchain.utils.Dataset; | ||||
import com.jd.blockchain.utils.Transactional; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
/** | /** | ||||
@@ -39,6 +41,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
private final Bytes dataKeyPrefix; | private final Bytes dataKeyPrefix; | ||||
private final Bytes merkleKeyPrefix; | private final Bytes merkleKeyPrefix; | ||||
@SuppressWarnings("unchecked") | |||||
private static final DataEntry<Bytes, byte[]>[] EMPTY_ENTRIES = new DataEntry[0]; | |||||
private BufferedKVStorage bufferedStorage; | private BufferedKVStorage bufferedStorage; | ||||
private VersioningKVStorage valueStorage; | private VersioningKVStorage valueStorage; | ||||
@@ -162,11 +167,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
return merkleTree.getDataCount(); | return merkleTree.getDataCount(); | ||||
} | } | ||||
/** | |||||
* 返回理论上允许的最大数据索引; | |||||
* | |||||
* @return | |||||
*/ | |||||
public long getMaxIndex() { | public long getMaxIndex() { | ||||
return merkleTree.getMaxSn(); | return merkleTree.getMaxSn(); | ||||
} | } | ||||
public byte[][] getLatestValues(int fromIndex, int count) { | |||||
public byte[][] getLatestValues(long fromIndex, int count) { | |||||
if (count > LedgerConsts.MAX_LIST_COUNT) { | if (count > LedgerConsts.MAX_LIST_COUNT) { | ||||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | ||||
} | } | ||||
@@ -182,13 +192,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
return values; | return values; | ||||
} | } | ||||
public DataEntry<Bytes, byte[]>[] getLatestDataEntries(int fromIndex, int count) { | |||||
public DataEntry<Bytes, byte[]>[] getLatestDataEntries(long fromIndex, int count) { | |||||
if (count > LedgerConsts.MAX_LIST_COUNT) { | if (count > LedgerConsts.MAX_LIST_COUNT) { | ||||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | ||||
} | } | ||||
if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | ||||
throw new IllegalArgumentException("Index out of bound!"); | throw new IllegalArgumentException("Index out of bound!"); | ||||
} | } | ||||
if (count == 0) { | |||||
return EMPTY_ENTRIES; | |||||
} | |||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
DataEntry<Bytes, byte[]>[] values = new DataEntry[count]; | DataEntry<Bytes, byte[]>[] values = new DataEntry[count]; | ||||
byte[] bytesValue; | byte[] bytesValue; | ||||
@@ -201,6 +214,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
return values; | 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; | * get the data at the specific index; | ||||
* | * | ||||
@@ -505,6 +531,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
return new VersioningKVData<Bytes, byte[]>(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) { | public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | ||||
DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version); | DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version); | ||||
if (dataEntry == null) { | if (dataEntry == null) { | ||||
@@ -586,4 +622,119 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Byt | |||||
merkleTree.cancel(); | merkleTree.cancel(); | ||||
snGenerator = new MerkleSequenceSNGenerator(merkleTree); | 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; | |||||
} | |||||
} | |||||
} | } |
@@ -10,7 +10,7 @@ import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.ContractInfo; | import com.jd.blockchain.ledger.ContractInfo; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | import com.jd.blockchain.ledger.DataAccountKVSetOperation; | ||||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | import com.jd.blockchain.ledger.DataAccountRegisterOperation; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.TypedKVEntry; | |||||
import com.jd.blockchain.ledger.KVInfoVO; | import com.jd.blockchain.ledger.KVInfoVO; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | import com.jd.blockchain.ledger.LedgerAdminInfo; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
@@ -172,17 +172,17 @@ public class ContractLedgerContext implements LedgerContext { | |||||
} | } | ||||
@Override | @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); | return innerQueryService.getDataEntries(ledgerHash, address, keys); | ||||
} | } | ||||
@Override | @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); | return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO); | ||||
} | } | ||||
@Override | @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); | return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count); | ||||
} | } | ||||
@@ -3,7 +3,7 @@ package test.com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.contract.ContractEventContext; | import com.jd.blockchain.contract.ContractEventContext; | ||||
import com.jd.blockchain.contract.ContractLifecycleAware; | import com.jd.blockchain.contract.ContractLifecycleAware; | ||||
import com.jd.blockchain.contract.EventProcessingAware; | import com.jd.blockchain.contract.EventProcessingAware; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.TypedKVEntry; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
public class TxTestContractImpl implements TxTestContract, ContractLifecycleAware, EventProcessingAware { | public class TxTestContractImpl implements TxTestContract, ContractLifecycleAware, EventProcessingAware { | ||||
@@ -16,7 +16,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar | |||||
@Override | @Override | ||||
public boolean testReadable() { | public boolean testReadable() { | ||||
KVDataEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||||
TypedKVEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), | |||||
dataAddress.toBase58(), KEY)[0]; | dataAddress.toBase58(), KEY)[0]; | ||||
String text1 = (String) v1.getValue(); | String text1 = (String) v1.getValue(); | ||||
System.out.printf("k1=%s, version=%s \r\n", text1, v1.getVersion()); | 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); | System.out.printf("new value = %s\r\n", newValue); | ||||
eventContext.getLedger().dataAccount(dataAddress).setText(KEY, newValue, v1.getVersion()); | 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]; | dataAddress.toBase58(), KEY)[0]; | ||||
System.out.printf("---- read new value ----\r\nk1=%s, version=%s \r\n", v2.getValue(), v2.getVersion()); | System.out.printf("---- read new value ----\r\nk1=%s, version=%s \r\n", v2.getValue(), v2.getVersion()); | ||||
@@ -48,7 +48,8 @@ public class AccountSetTest { | |||||
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); | BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); | ||||
accset.register(userKey.getAddress(), userKey.getPubKey()); | accset.register(userKey.getAddress(), userKey.getPubKey()); | ||||
//尚未提交之前,可以检索到账户的存在,但版本仍然标记为 -1; | |||||
MerkleAccount userAcc = accset.getAccount(userKey.getAddress()); | MerkleAccount userAcc = accset.getAccount(userKey.getAddress()); | ||||
assertNotNull(userAcc); | assertNotNull(userAcc); | ||||
assertTrue(accset.contains(userKey.getAddress())); | assertTrue(accset.contains(userKey.getAddress())); | ||||
@@ -6,8 +6,9 @@ import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | import com.jd.blockchain.consts.DataCodes; | ||||
@DataContract(code= DataCodes.CONTRACT_ACCOUNT_HEADER) | @DataContract(code= DataCodes.CONTRACT_ACCOUNT_HEADER) | ||||
public interface ContractInfo extends BlockchainIdentity { | |||||
public interface ContractInfo extends BlockchainIdentity, MerkleSnapshot { | |||||
@DataField(order=4, primitiveType= PrimitiveType.BYTES) | @DataField(order=4, primitiveType= PrimitiveType.BYTES) | ||||
byte[] getChainCode(); | byte[] getChainCode(); | ||||
} | } |
@@ -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.getBytes().toUTF8String(); | |||||
case BYTES: | |||||
return ByteArray.toHex(bytesValue.getBytes().toBytes()); | |||||
case INT64: | |||||
return BytesUtils.toLong(bytesValue.getBytes().toBytes()); | |||||
case JSON: | |||||
return bytesValue.getBytes().toUTF8String(); | |||||
case XML: | |||||
return bytesValue.getBytes().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.getBytes(); | |||||
} | |||||
/** | |||||
* 返回 8 位整数值; | |||||
* <p> | |||||
* | |||||
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; | |||||
* <p> | |||||
* | |||||
* 无效类型将引发 {@link IllegalStateException} 异常; | |||||
* | |||||
* @return | |||||
*/ | |||||
public byte tinyValue() { | |||||
if (DataType.INT8 == getType()) { | |||||
return bytesValue.getBytes().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.getBytes().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.getBytes().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.getBytes().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.getBytes().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.getBytes().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.getBytes().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.getBytes().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); | |||||
// } | |||||
} |
@@ -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; | package com.jd.blockchain.ledger; | ||||
public interface KVDataEntry { | |||||
public interface TypedKVEntry { | |||||
/** | /** | ||||
* 键名; | * 键名; | ||||
@@ -33,4 +33,12 @@ public interface KVDataEntry { | |||||
*/ | */ | ||||
Object getValue(); | 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())); | |||||
} | |||||
} | } |
@@ -16,9 +16,9 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||||
* | * | ||||
*/ | */ | ||||
public class TypedValue implements BytesValue { | public class TypedValue implements BytesValue { | ||||
public static final BytesValue NIL = new TypedValue(); | public static final BytesValue NIL = new TypedValue(); | ||||
private DataType type; | private DataType type; | ||||
private Bytes value; | private Bytes value; | ||||
@@ -31,16 +31,19 @@ public class TypedValue implements BytesValue { | |||||
this.type = type; | this.type = type; | ||||
this.value = bytes; | this.value = bytes; | ||||
} | } | ||||
private TypedValue(BytesValue bytesValue) { | private TypedValue(BytesValue bytesValue) { | ||||
this.type = bytesValue.getType(); | |||||
this.value = bytesValue.getBytes(); | |||||
if (bytesValue == null) { | |||||
this.type = DataType.NIL; | |||||
} else { | |||||
this.type = bytesValue.getType(); | |||||
this.value = bytesValue.getBytes(); | |||||
} | |||||
} | } | ||||
private TypedValue() { | private TypedValue() { | ||||
this.type = DataType.NIL; | this.type = DataType.NIL; | ||||
} | } | ||||
@Override | @Override | ||||
public DataType getType() { | public DataType getType() { | ||||
@@ -229,8 +232,7 @@ public class TypedValue implements BytesValue { | |||||
if (DataType.BIG_INT == type) { | if (DataType.BIG_INT == type) { | ||||
return toBigInteger(); | return toBigInteger(); | ||||
} | } | ||||
throw new IllegalStateException( | |||||
String.format("Type [%s] cannot be convert to BigInteger!", type)); | |||||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to BigInteger!", type)); | |||||
} | } | ||||
private BigInteger toBigInteger() { | private BigInteger toBigInteger() { | ||||
@@ -280,8 +282,7 @@ public class TypedValue implements BytesValue { | |||||
if (DataType.TIMESTAMP == type) { | if (DataType.TIMESTAMP == type) { | ||||
return toDatetime(); | return toDatetime(); | ||||
} | } | ||||
throw new IllegalStateException( | |||||
String.format("Type [%s] cannot be convert to datetime!", type)); | |||||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to datetime!", type)); | |||||
} | } | ||||
private Date toDatetime() { | private Date toDatetime() { | ||||
@@ -346,8 +347,7 @@ public class TypedValue implements BytesValue { | |||||
if (DataType.HASH_DIGEST == type) { | if (DataType.HASH_DIGEST == type) { | ||||
return toHashDegist(); | return toHashDegist(); | ||||
} | } | ||||
throw new IllegalStateException( | |||||
String.format("Type [%s] cannot be convert to hash digest!", type)); | |||||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to hash digest!", type)); | |||||
} | } | ||||
private HashDigest toHashDegist() { | private HashDigest toHashDegist() { | ||||
@@ -375,14 +375,13 @@ public class TypedValue implements BytesValue { | |||||
if (DataType.SIGNATURE_DIGEST == type) { | if (DataType.SIGNATURE_DIGEST == type) { | ||||
return toSignatureDigest(); | return toSignatureDigest(); | ||||
} | } | ||||
throw new IllegalStateException( | |||||
String.format("Type [%s] cannot be convert to signature digest!", type)); | |||||
throw new IllegalStateException(String.format("Type [%s] cannot be convert to signature digest!", type)); | |||||
} | } | ||||
private SignatureDigest toSignatureDigest() { | private SignatureDigest toSignatureDigest() { | ||||
return new SignatureDigest(toBytesArray()); | return new SignatureDigest(toBytesArray()); | ||||
} | } | ||||
public static TypedValue wrap(BytesValue value) { | public static TypedValue wrap(BytesValue value) { | ||||
return new TypedValue(value); | return new TypedValue(value); | ||||
} | } | ||||
@@ -5,7 +5,7 @@ import org.springframework.cglib.core.Block; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.ContractInfo; | 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.KVInfoVO; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | import com.jd.blockchain.ledger.LedgerAdminInfo; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
@@ -264,9 +264,9 @@ public interface BlockchainQueryService { | |||||
* @param keys | * @param keys | ||||
* @return | * @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> | * 返回指定数据账户中KV数据的总数; <br> | ||||
@@ -287,7 +287,7 @@ public interface BlockchainQueryService { | |||||
* 如果参数值为 -1,则返回全部的记录;<br> | * 如果参数值为 -1,则返回全部的记录;<br> | ||||
* @return | * @return | ||||
*/ | */ | ||||
KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||||
/** | /** | ||||
* 返回合约账户信息; | * 返回合约账户信息; | ||||
@@ -3,7 +3,6 @@ package com.jd.blockchain.peer.web; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import com.jd.blockchain.ledger.*; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.web.bind.annotation.PathVariable; | import org.springframework.web.bind.annotation.PathVariable; | ||||
import org.springframework.web.bind.annotation.RequestBody; | 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.contract.ContractException; | ||||
import com.jd.blockchain.crypto.HashDigest; | 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.ContractAccountQuery; | ||||
import com.jd.blockchain.ledger.core.DataAccount; | import com.jd.blockchain.ledger.core.DataAccount; | ||||
import com.jd.blockchain.ledger.core.DataAccountQuery; | 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.TransactionQuery; | ||||
import com.jd.blockchain.ledger.core.UserAccountQuery; | import com.jd.blockchain.ledger.core.UserAccountQuery; | ||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.utils.ArrayUtils; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.DataEntry; | |||||
import com.jd.blockchain.utils.DataIterator; | |||||
import com.jd.blockchain.utils.QueryUtil; | import com.jd.blockchain.utils.QueryUtil; | ||||
@RestController | @RestController | ||||
@@ -72,7 +90,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
} | } | ||||
return null; | return null; | ||||
} | } | ||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/admininfo") | @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/admininfo") | ||||
@Override | @Override | ||||
public LedgerAdminInfo getLedgerAdminInfo(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | public LedgerAdminInfo getLedgerAdminInfo(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { | ||||
@@ -337,7 +355,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") | ||||
@Override | @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) { | @PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { | ||||
if (keys == null || keys.length == 0) { | if (keys == null || keys.length == 0) { | ||||
return null; | return null; | ||||
@@ -347,15 +365,15 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||||
long ver; | long ver; | ||||
for (int i = 0; i < entries.length; i++) { | for (int i = 0; i < entries.length; i++) { | ||||
ver = dataAccount.getDataset().getVersion(keys[i]); | ver = dataAccount.getDataset().getVersion(keys[i]); | ||||
if (ver < 0) { | if (ver < 0) { | ||||
entries[i] = new KVDataObject(keys[i], -1, null); | |||||
entries[i] = new TypedKVData(keys[i], -1, null); | |||||
} else { | } else { | ||||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | ||||
entries[i] = new KVDataObject(keys[i], ver, value); | |||||
entries[i] = new TypedKVData(keys[i], ver, value); | |||||
} | } | ||||
} | } | ||||
@@ -365,7 +383,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") | ||||
@Override | @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) { | @PathVariable(name = "address") String address, @RequestBody KVInfoVO kvInfoVO) { | ||||
// parse kvInfoVO; | // parse kvInfoVO; | ||||
List<String> keyList = new ArrayList<>(); | List<String> keyList = new ArrayList<>(); | ||||
@@ -396,21 +414,21 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
KVDataEntry[] entries = new KVDataEntry[keys.length]; | |||||
TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||||
long ver = -1; | long ver = -1; | ||||
for (int i = 0; i < entries.length; i++) { | for (int i = 0; i < entries.length; i++) { | ||||
// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | ||||
ver = versions[i]; | ver = versions[i]; | ||||
if (ver < 0) { | if (ver < 0) { | ||||
entries[i] = new KVDataObject(keys[i], -1, null); | |||||
entries[i] = new TypedKVData(keys[i], -1, null); | |||||
} else { | } else { | ||||
if (dataAccount.getDataset().getDataCount() == 0 | if (dataAccount.getDataset().getDataCount() == 0 | ||||
|| dataAccount.getDataset().getValue(keys[i], ver) == null) { | || dataAccount.getDataset().getValue(keys[i], ver) == null) { | ||||
// is the address is not exist; the result is 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 { | } else { | ||||
BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | ||||
entries[i] = new KVDataObject(keys[i], ver, value); | |||||
entries[i] = new TypedKVData(keys[i], ver, value); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -421,7 +439,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
@RequestMapping(method = { RequestMethod.GET, | @RequestMapping(method = { RequestMethod.GET, | ||||
RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||||
public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | |||||
@PathVariable(name = "address") String address, | @PathVariable(name = "address") String address, | ||||
@RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, | ||||
@RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { | ||||
@@ -431,15 +449,21 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | ||||
int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); | |||||
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") | @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") | ||||
@Override | @Override | ||||
public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | ||||
@PathVariable(name = "address") String address) { | @PathVariable(name = "address") String address) { | ||||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | ||||
@@ -451,7 +475,7 @@ public class LedgerQueryController implements BlockchainQueryService { | |||||
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") | @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") | ||||
@Override | @Override | ||||
public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, | ||||
@PathVariable(name = "address") String address) { | |||||
@PathVariable(name = "address") String address) { | |||||
LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | LedgerQuery ledger = ledgerService.getLedger(ledgerHash); | ||||
LedgerBlock block = ledger.getLatestBlock(); | LedgerBlock block = ledger.getLatestBlock(); | ||||
ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | ||||
@@ -39,14 +39,14 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||||
public class ClientResolveUtil { | public class ClientResolveUtil { | ||||
public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||||
public static TypedKVEntry[] read(TypedKVEntry[] kvDataEntries) { | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | if (kvDataEntries == null || kvDataEntries.length == 0) { | ||||
return kvDataEntries; | return kvDataEntries; | ||||
} | } | ||||
KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||||
TypedKVEntry[] resolveKvDataEntries = new TypedKVEntry[kvDataEntries.length]; | |||||
// kvDataEntries是代理对象,需要处理 | // kvDataEntries是代理对象,需要处理 | ||||
for (int i = 0; i < kvDataEntries.length; i++) { | for (int i = 0; i < kvDataEntries.length; i++) { | ||||
KVDataEntry kvDataEntry = kvDataEntries[i]; | |||||
TypedKVEntry kvDataEntry = kvDataEntries[i]; | |||||
String key = kvDataEntry.getKey(); | String key = kvDataEntry.getKey(); | ||||
long version = kvDataEntry.getVersion(); | long version = kvDataEntry.getVersion(); | ||||
DataType dataType = kvDataEntry.getType(); | DataType dataType = kvDataEntry.getType(); | ||||
@@ -330,7 +330,7 @@ public class ClientResolveUtil { | |||||
} | } | ||||
public static class KvData implements KVDataEntry { | |||||
public static class KvData implements TypedKVEntry { | |||||
private String key; | private String key; | ||||
@@ -3,7 +3,7 @@ package com.jd.blockchain.sdk.proxy; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.ContractInfo; | 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.KVInfoVO; | ||||
import com.jd.blockchain.ledger.LedgerAdminInfo; | import com.jd.blockchain.ledger.LedgerAdminInfo; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
@@ -161,20 +161,20 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||||
} | } | ||||
@Override | @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); | return ClientResolveUtil.read(kvDataEntries); | ||||
} | } | ||||
@Override | @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); | return ClientResolveUtil.read(kvDataEntries); | ||||
} | } | ||||
@Override | @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); | return ClientResolveUtil.read(kvDataEntries); | ||||
} | } | ||||
@@ -504,13 +504,13 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||||
*/ | */ | ||||
@HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries") | @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries") | ||||
@Override | @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, | @PathParam(name="address") String address, | ||||
@RequestParam(name="keys", array = true) String... keys); | @RequestParam(name="keys", array = true) String... keys); | ||||
@HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") | @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") | ||||
@Override | @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, | @PathParam(name="address") String address, | ||||
@RequestBody KVInfoVO kvInfoVO); | @RequestBody KVInfoVO kvInfoVO); | ||||
@@ -531,7 +531,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService | |||||
*/ | */ | ||||
@HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") | ||||
@Override | @Override | ||||
KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, | |||||
TypedKVEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, | |||||
@PathParam(name = "address") String address, | @PathParam(name = "address") String address, | ||||
@RequestParam(name = "fromIndex", required = false) int fromIndex, | @RequestParam(name = "fromIndex", required = false) int fromIndex, | ||||
@RequestParam(name = "count", required = false) int count); | @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.contract.EventProcessingAware; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | 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; | 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); | assetHolderAddress); | ||||
// 计算资产的发行总数; | // 计算资产的发行总数; | ||||
KVDataObject currTotal = (KVDataObject) kvEntries[0]; | |||||
TypedKVData currTotal = (TypedKVData) kvEntries[0]; | |||||
long newTotal = currTotal.longValue() + amount; | long newTotal = currTotal.longValue() + amount; | ||||
eventContext.getLedger().dataAccount(ASSET_ADDRESS).setInt64(KEY_TOTAL, newTotal, currTotal.getVersion()); | 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; | long newHodlerAmount = holderAmount.longValue() + amount; | ||||
eventContext.getLedger().dataAccount(ASSET_ADDRESS) | eventContext.getLedger().dataAccount(ASSET_ADDRESS) | ||||
.setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) | .setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) | ||||
@@ -77,10 +77,10 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { | |||||
checkSignerPermission(fromAddress); | checkSignerPermission(fromAddress); | ||||
// 查询现有的余额; | // 查询现有的余额; | ||||
KVDataEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, | |||||
TypedKVEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, | |||||
fromAddress, toAddress); | 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 fromBalance = fromBalanceKV.getVersion() == -1 ? 0 : (long) fromBalanceKV.getValue(); | ||||
long toBalance = toBalanceKV.getVersion() == -1 ? 0 : (long) toBalanceKV.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.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
import com.jd.blockchain.ledger.Transaction; | import com.jd.blockchain.ledger.Transaction; | ||||
@@ -67,7 +67,7 @@ public class SDKDemo_Query { | |||||
// 获取数据; | // 获取数据; | ||||
String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | ||||
String[] objKeys = new String[] { "x001", "x002" }; | 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(); | 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.contract.TransferContract; | ||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | 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.PreparedTransaction; | ||||
import com.jd.blockchain.ledger.TransactionResponse; | import com.jd.blockchain.ledger.TransactionResponse; | ||||
import com.jd.blockchain.ledger.TransactionTemplate; | 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) { | 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) { | if (kvDataEntries == null || kvDataEntries.length == 0) { | ||||
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | ||||
} | } | ||||
KVDataEntry kvDataEntry = kvDataEntries[0]; | |||||
TypedKVEntry kvDataEntry = kvDataEntries[0]; | |||||
if (kvDataEntry.getVersion() == -1) { | if (kvDataEntry.getVersion() == -1) { | ||||
return 0L; | return 0L; | ||||
} | } | ||||
@@ -79,11 +79,11 @@ public class SDK_Contract_Random_Demo extends SDK_Base_Demo { | |||||
} | } | ||||
private long readByKvOperation(String address, String account) { | 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) { | if (kvDataEntries == null || kvDataEntries.length == 0) { | ||||
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | ||||
} | } | ||||
KVDataEntry kvDataEntry = kvDataEntries[0]; | |||||
TypedKVEntry kvDataEntry = kvDataEntries[0]; | |||||
if (kvDataEntry.getVersion() == -1) { | if (kvDataEntry.getVersion() == -1) { | ||||
return 0L; | return 0L; | ||||
} | } | ||||
@@ -107,9 +107,9 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { | |||||
// KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); | // KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); | ||||
// 获取数据账户下所有的KV列表 | // 获取数据账户下所有的KV列表 | ||||
KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); | |||||
TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); | |||||
if (kvData != null && kvData.length > 0) { | 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.key=" + kvDatum.getKey()); | ||||
System.out.println("kvData.version=" + kvDatum.getVersion()); | System.out.println("kvData.version=" + kvDatum.getVersion()); | ||||
System.out.println("kvData.type=" + kvDatum.getType()); | System.out.println("kvData.type=" + kvDatum.getType()); | ||||
@@ -24,7 +24,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.DigitalSignature; | import com.jd.blockchain.ledger.DigitalSignature; | ||||
import com.jd.blockchain.ledger.EndpointRequest; | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInfo; | import com.jd.blockchain.ledger.LedgerInfo; | ||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
@@ -149,8 +149,8 @@ public class SDK_GateWay_Query_Test_ { | |||||
String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; | ||||
String[] objKeys = new String[] { "x001", "x002" }; | 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.key=" + kvDatum.getKey()); | ||||
System.out.println("kvData.version=" + kvDatum.getVersion()); | System.out.println("kvData.version=" + kvDatum.getVersion()); | ||||
System.out.println("kvData.value=" + kvDatum.getValue()); | System.out.println("kvData.value=" + kvDatum.getValue()); | ||||
@@ -26,7 +26,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInfo; | import com.jd.blockchain.ledger.LedgerInfo; | ||||
import com.jd.blockchain.ledger.LedgerInitProperties; | import com.jd.blockchain.ledger.LedgerInitProperties; | ||||
@@ -216,8 +216,8 @@ public class IntegrationTest { | |||||
ledgerOfNode0.retrieveLatestBlock(); // 更新内存 | 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(); | String valHexText = (String) kvDataEntry.getValue(); | ||||
byte[] valBytes = HexUtils.decode(valHexText); | byte[] valBytes = HexUtils.decode(valHexText); | ||||
String valText = new String(valBytes); | String valText = new String(valBytes); | ||||
@@ -286,8 +286,8 @@ public class IntegrationBase { | |||||
assertEquals(txResp.getContentHash(), transactionHash); | assertEquals(txResp.getContentHash(), transactionHash); | ||||
assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); | assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); | ||||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); | |||||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); | |||||
for (TypedKVEntry kvDataEntry : kvDataEntries) { | |||||
assertEquals(dataKey, kvDataEntry.getKey()); | assertEquals(dataKey, kvDataEntry.getKey()); | ||||
String valHexText = (String) kvDataEntry.getValue(); | String valHexText = (String) kvDataEntry.getValue(); | ||||
assertEquals(dataVal, valHexText); | assertEquals(dataVal, valHexText); | ||||
@@ -26,7 +26,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInfo; | import com.jd.blockchain.ledger.LedgerInfo; | ||||
import com.jd.blockchain.ledger.LedgerInitProperties; | import com.jd.blockchain.ledger.LedgerInitProperties; | ||||
@@ -302,9 +302,9 @@ public class IntegrationTestAll4Redis { | |||||
assertEquals(txResp.getContentHash(), prepTx.getHash()); | assertEquals(txResp.getContentHash(), prepTx.getHash()); | ||||
assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); | assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); | ||||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), | |||||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), | |||||
dataKey); | dataKey); | ||||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||||
for (TypedKVEntry kvDataEntry : kvDataEntries) { | |||||
assertEquals(dataKey, kvDataEntry.getKey()); | assertEquals(dataKey, kvDataEntry.getKey()); | ||||
String valHexText = (String) kvDataEntry.getValue(); | String valHexText = (String) kvDataEntry.getValue(); | ||||
byte[] valBytes = HexUtils.decode(valHexText); | byte[] valBytes = HexUtils.decode(valHexText); | ||||
@@ -23,7 +23,7 @@ import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; | |||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | 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.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInitProperties; | import com.jd.blockchain.ledger.LedgerInitProperties; | ||||
import com.jd.blockchain.ledger.PreparedTransaction; | import com.jd.blockchain.ledger.PreparedTransaction; | ||||
@@ -214,7 +214,7 @@ public class IntegrationTestDataAccount { | |||||
e.printStackTrace(); | e.printStackTrace(); | ||||
} | } | ||||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", | |||||
TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", | |||||
"C", "D"); | "C", "D"); | ||||
for (int i = 0; i < kvDataEntries.length; i++) { | for (int i = 0; i < kvDataEntries.length; i++) { | ||||
Object result = kvDataEntries[i].getValue(); | Object result = kvDataEntries[i].getValue(); | ||||
@@ -9,17 +9,29 @@ import java.util.*; | |||||
*/ | */ | ||||
public abstract class ArrayUtils { | public abstract class ArrayUtils { | ||||
private ArrayUtils() { | private ArrayUtils() { | ||||
} | } | ||||
public static <T, R> R[] castTo(T[] objs, Class<R> clazz, CastFunction<T, R> cf) { | |||||
if (objs == null) { | |||||
return null; | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
R[] array = (R[]) Array.newInstance(clazz, objs.length); | |||||
for (int i = 0; i < objs.length; i++) { | |||||
array[i] = cf.cast(objs[i]); | |||||
} | |||||
return array; | |||||
} | |||||
public static <T> T[] singleton(T obj, Class<T> clazz) { | public static <T> T[] singleton(T obj, Class<T> clazz) { | ||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
T[] array = (T[]) Array.newInstance(clazz, 1); | T[] array = (T[]) Array.newInstance(clazz, 1); | ||||
array[0] = obj; | array[0] = obj; | ||||
return array; | return array; | ||||
} | } | ||||
public static <T> T[] toArray(Iterator<T> itr, Class<T> clazz){ | |||||
public static <T> T[] toArray(Iterator<T> itr, Class<T> clazz) { | |||||
List<T> lst = new LinkedList<T>(); | List<T> lst = new LinkedList<T>(); | ||||
while (itr.hasNext()) { | while (itr.hasNext()) { | ||||
T t = (T) itr.next(); | T t = (T) itr.next(); | ||||
@@ -30,19 +42,19 @@ public abstract class ArrayUtils { | |||||
lst.toArray(array); | lst.toArray(array); | ||||
return array; | return array; | ||||
} | } | ||||
public static <T> T[] toArray(Collection<T> collection, Class<T> clazz){ | |||||
public static <T> T[] toArray(Collection<T> collection, Class<T> clazz) { | |||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
T[] array = (T[]) Array.newInstance(clazz, collection.size()); | T[] array = (T[]) Array.newInstance(clazz, collection.size()); | ||||
collection.toArray(array); | collection.toArray(array); | ||||
return array; | return array; | ||||
} | } | ||||
public static <T> List<T> asList(T[] array){ | |||||
public static <T> List<T> asList(T[] array) { | |||||
return asList(array, 0, array.length); | return asList(array, 0, array.length); | ||||
} | } | ||||
public static <T> Set<T> asSet(T[] array){ | |||||
public static <T> Set<T> asSet(T[] array) { | |||||
if (array == null || array.length == 0) { | if (array == null || array.length == 0) { | ||||
return Collections.emptySet(); | return Collections.emptySet(); | ||||
} | } | ||||
@@ -52,8 +64,8 @@ public abstract class ArrayUtils { | |||||
} | } | ||||
return set; | return set; | ||||
} | } | ||||
public static <T> SortedSet<T> asSortedSet(T[] array){ | |||||
public static <T> SortedSet<T> asSortedSet(T[] array) { | |||||
if (array == null || array.length == 0) { | if (array == null || array.length == 0) { | ||||
return Collections.emptySortedSet(); | return Collections.emptySortedSet(); | ||||
} | } | ||||
@@ -63,12 +75,12 @@ public abstract class ArrayUtils { | |||||
} | } | ||||
return set; | return set; | ||||
} | } | ||||
public static <T> List<T> asList(T[] array, int fromIndex){ | |||||
public static <T> List<T> asList(T[] array, int fromIndex) { | |||||
return asList(array, fromIndex, array.length); | return asList(array, fromIndex, array.length); | ||||
} | } | ||||
public static <T> List<T> asList(T[] array, int fromIndex, int toIndex){ | |||||
public static <T> List<T> asList(T[] array, int fromIndex, int toIndex) { | |||||
if (toIndex < fromIndex) { | if (toIndex < fromIndex) { | ||||
throw new IllegalArgumentException("The toIndex less than fromIndex!"); | throw new IllegalArgumentException("The toIndex less than fromIndex!"); | ||||
} | } | ||||
@@ -78,10 +90,33 @@ public abstract class ArrayUtils { | |||||
if (toIndex > array.length) { | if (toIndex > array.length) { | ||||
throw new IllegalArgumentException("The toIndex great than the length of array!"); | throw new IllegalArgumentException("The toIndex great than the length of array!"); | ||||
} | } | ||||
if (fromIndex == toIndex) { | if (fromIndex == toIndex) { | ||||
return Collections.emptyList(); | return Collections.emptyList(); | ||||
} | } | ||||
return new ReadonlyArrayListWrapper<T>(array, fromIndex, toIndex); | return new ReadonlyArrayListWrapper<T>(array, fromIndex, toIndex); | ||||
} | } | ||||
public static interface CastFunction<T, R> { | |||||
public R cast(T data); | |||||
} | |||||
/** | |||||
* Reverse all elements of the specified array; <br> | |||||
* | |||||
* @param <T> | |||||
* @param array | |||||
*/ | |||||
public static <T> void reverse(T[] array) { | |||||
if (array == null || array.length < 2) { | |||||
return; | |||||
} | |||||
T t; | |||||
for (int i = 0, j = array.length - 1; i < j; i++, j--) { | |||||
t = array[i]; | |||||
array[i] = array[j]; | |||||
array[j] = t; | |||||
} | |||||
} | |||||
} | } |
@@ -1,7 +1,5 @@ | |||||
package com.jd.blockchain.utils; | package com.jd.blockchain.utils; | ||||
import java.io.File; | |||||
/** | /** | ||||
* | * | ||||
* @author zhaogw | * @author zhaogw | ||||
@@ -1,7 +1,7 @@ | |||||
package com.jd.blockchain.utils; | package com.jd.blockchain.utils; | ||||
/** | /** | ||||
* 版本化的键值数据项; | |||||
* Versioning Key-Value data entry; | |||||
* | * | ||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
@@ -0,0 +1,21 @@ | |||||
package com.jd.blockchain.utils; | |||||
/** | |||||
* 数据迭代器; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
* @param <K> | |||||
* @param <V> | |||||
*/ | |||||
public interface DataIterator<K, V> { | |||||
void skip(long count); | |||||
DataEntry<K, V> next(); | |||||
DataEntry<K, V>[] next(int count); | |||||
boolean hasNext(); | |||||
} |
@@ -1,34 +0,0 @@ | |||||
package com.jd.blockchain.utils; | |||||
import java.lang.reflect.Type; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.springframework.util.TypeUtils; | |||||
public abstract class DataTypeUtils { | |||||
private static Map<Class<?>, Class<?>> wrapperTypes = new HashMap<Class<?>, Class<?>>(); | |||||
static{ | |||||
wrapperTypes.put(long.class, Long.class); | |||||
wrapperTypes.put(int.class, Integer.class); | |||||
wrapperTypes.put(char.class, Character.class); | |||||
wrapperTypes.put(byte.class, Byte.class); | |||||
wrapperTypes.put(boolean.class, Boolean.class); | |||||
} | |||||
public static boolean isAssignable(Type lhsType, Type rhsType) { | |||||
boolean assignable = TypeUtils.isAssignable(lhsType, rhsType); | |||||
if (assignable) { | |||||
return true; | |||||
} | |||||
if (lhsType instanceof Class) { | |||||
Class<?> lhsClass = (Class<?>) lhsType; | |||||
} | |||||
return false; | |||||
} | |||||
} |
@@ -1,7 +1,20 @@ | |||||
package com.jd.blockchain.utils; | package com.jd.blockchain.utils; | ||||
/** | |||||
* Key-Value data set; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
* @param <K> | |||||
* @param <V> | |||||
*/ | |||||
public interface Dataset<K, V> { | public interface Dataset<K, V> { | ||||
/** | |||||
* Total count of data entries; | |||||
* | |||||
* @return | |||||
*/ | |||||
long getDataCount(); | long getDataCount(); | ||||
/** | /** | ||||
@@ -26,17 +39,6 @@ public interface Dataset<K, V> { | |||||
*/ | */ | ||||
long setValue(K key, V value, long version); | long setValue(K key, V value, long 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 | |||||
// */ | |||||
// byte[] getValue(String key, long version); | |||||
/** | /** | ||||
* Return the specified version's value;<br> | * Return the specified version's value;<br> | ||||
* | * | ||||
@@ -48,47 +50,51 @@ public interface Dataset<K, V> { | |||||
*/ | */ | ||||
V getValue(K key, long version); | V getValue(K key, long version); | ||||
// /** | |||||
// * Return the latest version's value; | |||||
// * | |||||
// * @param key | |||||
// * @return return null if not exist; | |||||
// */ | |||||
// byte[] getValue(String key); | |||||
/** | /** | ||||
* Return the latest version's value; | |||||
* Return the value of the latest version; | |||||
* | * | ||||
* @param key | * @param key | ||||
* @return return null if not exist; | * @return return null if not exist; | ||||
*/ | */ | ||||
V getValue(K key); | V getValue(K key); | ||||
// /** | |||||
// * Return the latest version entry associated the specified key; If the key | |||||
// * doesn't exist, then return -1; | |||||
// * | |||||
// * @param key | |||||
// * @return | |||||
// */ | |||||
// long getVersion(String key); | |||||
/** | /** | ||||
* Return the latest version entry associated the specified key; If the key | |||||
* doesn't exist, then return -1; | |||||
* Return the latest version number of the specified key; | |||||
* | * | ||||
* @param key | * @param key | ||||
* @return | |||||
* @return The version number of the specified key; If the key doesn't exist, | |||||
* then return -1; | |||||
*/ | */ | ||||
long getVersion(K key); | long getVersion(K key); | ||||
/** | /** | ||||
* Return data entry | |||||
* | * | ||||
* @param key | * @param key | ||||
* @return Null if the key doesn't exist! | * @return Null if the key doesn't exist! | ||||
*/ | */ | ||||
DataEntry<K, V> getDataEntry(K key); | DataEntry<K, V> getDataEntry(K key); | ||||
/** | |||||
* | |||||
* @param key | |||||
* @param version | |||||
* @return | |||||
*/ | |||||
DataEntry<K, V> getDataEntry(K key, long version); | DataEntry<K, V> getDataEntry(K key, long version); | ||||
/** | |||||
* Ascending iterator; | |||||
* | |||||
* @return | |||||
*/ | |||||
DataIterator<K, V> iterator(); | |||||
/** | |||||
* Descending iterator; | |||||
* | |||||
* @return | |||||
*/ | |||||
DataIterator<K, V> iteratorDesc(); | |||||
} | } |
@@ -1,8 +1,12 @@ | |||||
package com.jd.blockchain.utils; | package com.jd.blockchain.utils; | ||||
/** | |||||
* Helper for {@link Dataset}; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public class DatasetHelper { | public class DatasetHelper { | ||||
public static final TypeMapper<Bytes, String> UTF8_STRING_BYTES_MAPPER = new TypeMapper<Bytes, String>() { | public static final TypeMapper<Bytes, String> UTF8_STRING_BYTES_MAPPER = new TypeMapper<Bytes, String>() { | ||||
@@ -29,7 +33,7 @@ public class DatasetHelper { | |||||
return Bytes.fromString(t2); | return Bytes.fromString(t2); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* 适配两个不同类型参数的数据集; | * 适配两个不同类型参数的数据集; | ||||
* | * | ||||
@@ -121,8 +125,8 @@ public class DatasetHelper { | |||||
T2 decode(T1 t1); | T2 decode(T1 t1); | ||||
} | } | ||||
private static class EmptyMapper<T> implements TypeMapper<T, T>{ | |||||
private static class EmptyMapper<T> implements TypeMapper<T, T> { | |||||
@Override | @Override | ||||
public T encode(T t) { | public T encode(T t) { | ||||
@@ -133,7 +137,7 @@ public class DatasetHelper { | |||||
public T decode(T t) { | public T decode(T t) { | ||||
return t; | return t; | ||||
} | } | ||||
} | } | ||||
private static class DatasetUpdatingMonitor<K, V> implements Dataset<K, V> { | private static class DatasetUpdatingMonitor<K, V> implements Dataset<K, V> { | ||||
@@ -186,6 +190,16 @@ public class DatasetHelper { | |||||
return dataset.getDataEntry(key, version); | return dataset.getDataEntry(key, version); | ||||
} | } | ||||
@Override | |||||
public DataIterator<K, V> iterator() { | |||||
return dataset.iterator(); | |||||
} | |||||
@Override | |||||
public DataIterator<K, V> iteratorDesc() { | |||||
return dataset.iteratorDesc(); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -269,6 +283,73 @@ public class DatasetHelper { | |||||
return new KeyValueEntry<K2, V2>(key, v, entry.getVersion()); | return new KeyValueEntry<K2, V2>(key, v, entry.getVersion()); | ||||
} | } | ||||
@Override | |||||
public DataIterator<K2, V2> iterator() { | |||||
DataIterator<K1, V1> it = dataset.iterator(); | |||||
return new DataIteratorAdapter<K1, K2, V1, V2>(it, keyMapper, valueMapper); | |||||
} | |||||
@Override | |||||
public DataIterator<K2, V2> iteratorDesc() { | |||||
DataIterator<K1, V1> it = dataset.iteratorDesc(); | |||||
return new DataIteratorAdapter<K1, K2, V1, V2>(it, keyMapper, valueMapper); | |||||
} | |||||
} | |||||
private static class DataIteratorAdapter<K1, K2, V1, V2> implements DataIterator<K2, V2> { | |||||
private DataIterator<K1, V1> iterator; | |||||
private TypeMapper<K1, K2> keyMapper; | |||||
private TypeMapper<V1, V2> valueMapper; | |||||
public DataIteratorAdapter(DataIterator<K1, V1> iterator, TypeMapper<K1, K2> keyMapper, | |||||
TypeMapper<V1, V2> valueMapper) { | |||||
this.iterator = iterator; | |||||
this.keyMapper = keyMapper; | |||||
this.valueMapper = valueMapper; | |||||
} | |||||
@Override | |||||
public void skip(long count) { | |||||
iterator.skip(count); | |||||
} | |||||
@Override | |||||
public DataEntry<K2, V2> next() { | |||||
DataEntry<K1, V1> entry = iterator.next(); | |||||
return cast(entry); | |||||
} | |||||
private DataEntry<K2, V2> cast(DataEntry<K1, V1> entry) { | |||||
if (entry == null) { | |||||
return null; | |||||
} | |||||
K2 k = keyMapper.decode(entry.getKey()); | |||||
V2 v = valueMapper.decode(entry.getValue()); | |||||
return new KeyValueEntry<K2, V2>(k, v, entry.getVersion()); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
@Override | |||||
public DataEntry<K2, V2>[] next(int count) { | |||||
DataEntry<K1, V1>[] entries = iterator.next(count); | |||||
if (entries == null) { | |||||
return null; | |||||
} | |||||
if (entries.length == 0) { | |||||
return (DataEntry<K2, V2>[]) entries; | |||||
} | |||||
return ArrayUtils.castTo(entries, DataEntry.class, e -> cast(e)); | |||||
} | |||||
@Override | |||||
public boolean hasNext() { | |||||
return iterator.hasNext(); | |||||
} | |||||
} | } | ||||
private static class KeyValueEntry<K, V> implements DataEntry<K, V> { | private static class KeyValueEntry<K, V> implements DataEntry<K, V> { | ||||