Browse Source

temp;

tags/1.1.2^2
huanghaiquan 5 years ago
parent
commit
0debb28abc
59 changed files with 2202 additions and 654 deletions
  1. +4
    -0
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +0
    -2
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java
  3. +11
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java
  4. +8
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/BytesKeyMap.java
  5. +11
    -11
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
  6. +11
    -11
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
  7. +83
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccount.java
  8. +92
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccountSet.java
  9. +42
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java
  10. +10
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashProvable.java
  11. +14
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAccount.java
  12. +306
    -111
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java
  13. +12
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountHeader.java
  14. +62
    -128
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java
  15. +3
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java
  16. +96
    -81
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java
  17. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java
  18. +7
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/StringKeyMap.java
  19. +12
    -26
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java
  20. +4
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java
  21. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java
  22. +8
    -8
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java
  23. +7
    -7
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java
  24. +2
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java
  25. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java
  26. +6
    -6
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java
  27. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java
  28. +0
    -118
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java
  29. +4
    -4
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java
  30. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java
  31. +59
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java
  32. +44
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/HashProof.java
  33. +29
    -47
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java
  34. +455
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedBytesValue.java
  35. +472
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue_.java
  36. +12
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserAccountHeader.java
  37. +3
    -6
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java
  38. +2
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java
  39. +3
    -3
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java
  40. +2
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java
  41. +2
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java
  42. +2
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java
  43. +3
    -3
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java
  44. +9
    -9
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java
  45. +2
    -2
      source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java
  46. +4
    -4
      source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java
  47. +2
    -2
      source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java
  48. +4
    -3
      source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java
  49. +1
    -1
      source/storage/storage-redis/src/main/java/com/jd/blockchain/storage/service/impl/redis/RedisVerioningStorage.java
  50. +1
    -1
      source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java
  51. +0
    -20
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVEntry.java
  52. +2
    -1
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java
  53. +5
    -5
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java
  54. +1
    -1
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java
  55. +7
    -8
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java
  56. +1
    -1
      source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java
  57. +122
    -0
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/RegionMap.java
  58. +17
    -0
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/VersioningKVEntry.java
  59. +116
    -0
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/VersioningMap.java

+ 4
- 0
source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java View File

@@ -122,11 +122,15 @@ public interface DataCodes {
public static final int ACCOUNT_HEADER = 0x710;

public static final int USER_ACCOUNT_HEADER = 0x800;
public static final int USER_INFO = 0x801;

public static final int DATA = 0x900;

// contract related;
public static final int CONTRACT_ACCOUNT_HEADER = 0xA00;
public static final int CONTRACT_INFO = 0xA01;

// ...0xA19
public static final int HASH = 0xB00;


+ 0
- 2
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/impl/DynamicDataContract.java View File

@@ -21,8 +21,6 @@ class DynamicDataContract implements InvocationHandler {

private DataContractEncoderImpl contractEncoder;

// private BytesSlice contractBytes;

// 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段;
private BytesSlices[] dataSlices;



+ 11
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountQuery.java View File

@@ -1,12 +1,11 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.utils.Bytes;

public interface AccountQuery<T> extends MerkleProvable {

AccountHeader[] getHeaders(int fromIndex, int count);

/**
* 返回总数;
*
@@ -14,7 +13,15 @@ public interface AccountQuery<T> extends MerkleProvable {
*/
long getTotal();

BlockchainIdentity[] getHeaders(int fromIndex, int count);

boolean contains(Bytes address);
/**
* get proof of specified account;
*/
@Override
MerkleProof getProof(Bytes address);

/**
* 返回账户实例;


+ 8
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/BytesKeyMap.java View File

@@ -0,0 +1,8 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningMap;

public interface BytesKeyMap<V> extends VersioningMap<Bytes, V> {

}

+ 11
- 11
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java View File

@@ -2,7 +2,7 @@ package com.jd.blockchain.ledger.core;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.ContractInfo;
import com.jd.blockchain.ledger.MerkleProof;
@@ -44,16 +44,16 @@ public class ContractAccount implements ContractInfo {
}
public long setChaincode(byte[] chaincode, long version) {
BytesValue bytesValue = BytesData.fromBytes(chaincode);
return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version);
BytesValue bytesValue = TypedBytesValue.fromBytes(chaincode);
return accBase.setValue(CHAIN_CODE_KEY, bytesValue, version);
}
public byte[] getChainCode() {
return accBase.getBytes(CHAIN_CODE_KEY).getValue().toBytes();
return accBase.getValue(CHAIN_CODE_KEY).getValue().toBytes();
}
public byte[] getChainCode(long version) {
return accBase.getBytes(CHAIN_CODE_KEY, version).getValue().toBytes();
return accBase.getValue(CHAIN_CODE_KEY, version).getValue().toBytes();
}
public long getChaincodeVersion() {
@@ -61,18 +61,18 @@ public class ContractAccount implements ContractInfo {
}
public long setProperty(Bytes key, String value, long version) {
BytesValue bytesValue = BytesData.fromText(value);
return accBase.setBytes(encodePropertyKey(key), bytesValue, version);
BytesValue bytesValue = TypedBytesValue.fromText(value);
return accBase.setValue(encodePropertyKey(key), bytesValue, version);
}
public String getProperty(Bytes key) {
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key));
return BytesData.toText(bytesValue);
BytesValue bytesValue = accBase.getValue(encodePropertyKey(key));
return TypedBytesValue.toText(bytesValue);
}
public String getProperty(Bytes key, long version) {
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version);
return BytesData.toText(bytesValue);
BytesValue bytesValue = accBase.getValue(encodePropertyKey(key), version);
return TypedBytesValue.toText(bytesValue);
}
private Bytes encodePropertyKey(Bytes key) {


+ 11
- 11
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java View File

@@ -4,7 +4,7 @@ import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.KVDataObject;
@@ -67,7 +67,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* return -1;
*/
public long setBytes(Bytes key, BytesValue value, long version) {
return baseAccount.setBytes(key, value, version);
return baseAccount.setValue(key, value, version);
}
@@ -95,8 +95,8 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* return -1;
*/
public long setBytes(Bytes key, String value, long version) {
BytesValue bytesValue = BytesData.fromText(value);
return baseAccount.setBytes(key, bytesValue, version);
BytesValue bytesValue = TypedBytesValue.fromText(value);
return baseAccount.setValue(key, bytesValue, version);
}
/**
@@ -123,8 +123,8 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* return -1;
*/
public long setBytes(Bytes key, byte[] value, long version) {
BytesValue bytesValue = BytesData.fromBytes(value);
return baseAccount.setBytes(key, bytesValue, version);
BytesValue bytesValue = TypedBytesValue.fromBytes(value);
return baseAccount.setValue(key, bytesValue, version);
}
/**
@@ -156,7 +156,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return return null if not exist;
*/
public BytesValue getBytes(String key) {
return baseAccount.getBytes(Bytes.fromString(key));
return baseAccount.getValue(Bytes.fromString(key));
}
/**
@@ -166,7 +166,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return return null if not exist;
*/
public BytesValue getBytes(Bytes key) {
return baseAccount.getBytes(key);
return baseAccount.getValue(key);
}
/**
@@ -177,7 +177,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return return null if not exist;
*/
public BytesValue getBytes(String key, long version) {
return baseAccount.getBytes(Bytes.fromString(key), version);
return baseAccount.getValue(Bytes.fromString(key), version);
}
/**
@@ -188,7 +188,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return return null if not exist;
*/
public BytesValue getBytes(Bytes key, long version) {
return baseAccount.getBytes(key, version);
return baseAccount.getValue(key, version);
}
/**
@@ -206,7 +206,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return
*/
public KVDataEntry getDataEntry(Bytes key, long version) {
BytesValue value = baseAccount.getBytes(key, version);
BytesValue value = baseAccount.getValue(key, version);
if (value == null) {
return new KVDataObject(key.toUTF8String(), -1, null);
}else {


+ 83
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccount.java View File

@@ -0,0 +1,83 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningMap;

/**
* Super Type of concrete accounts, e.g. UserAccount, DataAccount,
* ContractAccount etc.;
*
* @author huanghaiquan
*
* @param <H> Type of Account Header;
*/
public class GenericAccount implements MerkleAccountHeader, MerkleProvable, Transactional {

private MerkleAccount merkleAccount;


/**
* 头部类型;
*
* @param headerType
*/
public GenericAccount(MerkleAccount merkleAccount) {
this.merkleAccount = merkleAccount;
}

@Override
public HashDigest getRootHash() {
return merkleAccount.getRootHash();
}

@Override
public MerkleProof getProof(Bytes key) {
key = buildInnerKey(key);
return merkleAccount.getProof(key);
}


@Override
public BlockchainIdentity getID() {
return merkleAccount.getID();
}

public TypedMap getDataset() {
VersioningMap<Bytes, BytesValue> state = merkleAccount.getDataset();
return new TypedMap(state);
}


@Override
public boolean isUpdated() {
return merkleAccount.isUpdated();
}

boolean isReadonly() {
return merkleAccount.isReadonly();
}

@Override
public void commit() {
merkleAccount.commit();
}

@Override
public void cancel() {
merkleAccount.cancel();
}

private Bytes buildInnerKey(Bytes key) {
// TODO Auto-generated method stub
return null;
}
}

+ 92
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/GenericAccountSet.java View File

@@ -0,0 +1,92 @@
//package com.jd.blockchain.ledger.core;
//
//import com.jd.blockchain.crypto.HashDigest;
//import com.jd.blockchain.ledger.AccountHeader;
//import com.jd.blockchain.ledger.CryptoSetting;
//import com.jd.blockchain.ledger.MerkleProof;
//import com.jd.blockchain.storage.service.ExPolicyKVStorage;
//import com.jd.blockchain.storage.service.VersioningKVStorage;
//import com.jd.blockchain.utils.Bytes;
//import com.jd.blockchain.utils.Transactional;
//
//public class GenericAccountSet<H extends AccountHeader, T extends GenericAccount<H>> implements AccountQuery<H, T>, Transactional {
//
// private Class<H> headerType;
//
// private MerkleAccountSet merkleAccountSet;
//
// public GenericAccountSet(Class<H> headerType, CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage,
// VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) {
// this(headerType, null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy);
// }
//
// public GenericAccountSet(Class<H> headerType, HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix,
// ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly,
// AccountAccessPolicy accessPolicy) {
// this.headerType = headerType;
// this.merkleAccountSet = new MerkleAccountSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, accessPolicy);
// }
//
// @Override
// public MerkleProof getProof(Bytes address) {
// return merkleAccountSet.getProof(address);
// }
//
// @Override
// public HashDigest getRootHash() {
// return merkleAccountSet.getRootHash();
// }
//
// @Override
// public boolean isUpdated() {
// return merkleAccountSet.isUpdated();
// }
//
// @Override
// public void commit() {
// merkleAccountSet.commit();
// }
//
// @Override
// public void cancel() {
// merkleAccountSet.cancel();
// }
//
// @Override
// public H[] getHeaders(int fromIndex, int count) {
// merkleAccountSet.getHeaders(fromIndex, count)
// return null;
// }
//
// @Override
// public long getTotal() {
// // TODO Auto-generated method stub
// return 0;
// }
//
// @Override
// public boolean contains(Bytes address) {
// // TODO Auto-generated method stub
// return false;
// }
//
// @Override
// public T getAccount(String address) {
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public T getAccount(Bytes address) {
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public T getAccount(Bytes address, long version) {
// // TODO Auto-generated method stub
// return null;
// }
//
//
//}

+ 42
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java View File

@@ -0,0 +1,42 @@
package com.jd.blockchain.ledger.core;

import java.util.ArrayList;
import java.util.List;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.HashProof;

/**
*
* @author huanghaiquan
*
*/
public class HashDegistList implements HashProof {

private List<HashDigest> proofs = new ArrayList<HashDigest>();

public HashDegistList() {
}

public HashDegistList(HashProof proof) {
concat(proof);
}

public void concat(HashProof proof) {
int levels = proof.getLevels();
for (int i = levels; i > -1; i--) {
proofs.add(proof.getHash(i));
}
}

@Override
public int getLevels() {
return proofs.size();
}

@Override
public HashDigest getHash(int level) {
return proofs.get(level);
}

}

+ 10
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashProvable.java View File

@@ -0,0 +1,10 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.HashProof;
import com.jd.blockchain.utils.Bytes;

public interface HashProvable {
HashProof getProof(Bytes key);
}

+ 14
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAccount.java View File

@@ -0,0 +1,14 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningMap;

public interface LedgerAccount {
BlockchainIdentity getID();
VersioningMap<Bytes, BytesValue> getDataset();
}

+ 306
- 111
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java View File

@@ -3,16 +3,20 @@ package com.jd.blockchain.ledger.core;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BlockchainIdentityData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.HashProof;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.ledger.MerkleSnapshot;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.VersioningMap;

/**
* 事务性的基础账户;
@@ -20,28 +24,26 @@ import com.jd.blockchain.utils.Transactional;
* @author huanghaiquan
*
*/
public class MerkleAccount implements AccountHeader, MerkleProvable, Transactional {
public class MerkleAccount implements LedgerAccount, HashProvable, MerkleSnapshot, Transactional {

private BlockchainIdentity bcid;
private static final Bytes HEADER_PREFIX = Bytes.fromString("HD/");
private static final Bytes DATA_PREFIX = Bytes.fromString("DT/");

protected MerkleDataSet dataset;
private static final Bytes KEY_PUBKEY = Bytes.fromString("PUBKEY");

/**
* Create a new Account with the specified address and pubkey; <br>
*
* At the same time, a empty merkle dataset is also created for this account,
* which is used for storing data of this account.<br>
*
* Note that, the blockchain identity of the account is not stored in the
* account's merkle dataset, but is stored by the outer invoker;
*
* @param address
* @param pubKey
*/
public MerkleAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) {
this(address, pubKey, null, cryptoSetting, keyPrefix, exStorage, verStorage, false);
}
private static final Bytes KEY_HEADER_ROOT = Bytes.fromString("HEADER");

private static final Bytes KEY_DATA_ROOT = Bytes.fromString("DATA");

private BlockchainIdentity accountID;

private MerkleDataSet rootDS;

private MerkleDatasetAdapter headerDS;

private MerkleDatasetAdapter dataDS;
protected long version;

/**
* Create a new Account with the specified address and pubkey; <br>
@@ -52,62 +54,101 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction
* Note that, the blockchain identity of the account is not stored in the
* account's merkle dataset, but is stored by the outer invoker;
*
* @param bcid
* @param cryptoSetting
* @param accountID 身份;
* @param version 版本;
* @param cryptoSetting 密码参数;
* @param keyPrefix 数据前缀;
* @param exStorage
* @param verStorage
* @param accessPolicy
*/
public MerkleAccount(BlockchainIdentity bcid, CryptoSetting cryptoSetting, String keyPrefix,
public MerkleAccount(BlockchainIdentity accountID, long version, CryptoSetting cryptoSetting, Bytes keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) {
this(bcid, null, cryptoSetting, keyPrefix, exStorage, verStorage, false);
this(accountID.getAddress(), accountID.getPubKey(), version, null, cryptoSetting, keyPrefix, exStorage,
verStorage, false);

savePubKey(accountID.getPubKey());
}

/**
* Create a account instance with the specified address and pubkey and load it's
* merkle dataset from the specified root hash. This merkle dateset is used for storing data
* of this account.<br>
* merkle dataset from the specified root hash. This merkle dateset is used for
* storing data of this account.<br>
*
* @param address
* @param pubKey
* @param dataRootHash merkle root hash of account's data; if set to a null value,
* an empty merkle dataset is created;
* @param accountID identity of this account;
* @param version
* @param dataRootHash merkle root hash of account's data; if set to a null
* value, an empty merkle dataset is created;
* @param cryptoSetting
* @param keyPrefix
* @param exStorage
* @param verStorage
* @param readonly
* @param accessPolicy
*/
public MerkleAccount(Bytes address, PubKey pubKey, HashDigest dataRootHash, CryptoSetting cryptoSetting,
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) {
this(new BlockchainIdentityData(address, pubKey), dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage,
public MerkleAccount(Bytes address, long version, HashDigest dataRootHash, CryptoSetting cryptoSetting,
Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) {
this(address, null, version, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly);
}

private MerkleAccount(Bytes address, PubKey pubKey, long version, HashDigest dataRootHash,
CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage,
boolean readonly) {
this.accountID = new BlockchainIdentityProxy(address, pubKey);
this.version = version;
this.rootDS = new MerkleDataSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly);

// 初始化数据;
DataChangedListener dataChangedListener = new DataChangedListener() {
@Override
public void onChanged(Bytes key, BytesValue value, long newVersion) {
onUpdated(keyPrefix, value, newVersion);
}
};

HashDigest headerRoot = loadHeaderRoot();
Bytes headerPrefix = keyPrefix.concat(HEADER_PREFIX);
MerkleDataSet headerDataset = new MerkleDataSet(headerRoot, cryptoSetting, headerPrefix, exStorage, verStorage,
readonly);
this.headerDS = new MerkleDatasetAdapter(headerDataset, dataChangedListener);

HashDigest dataRoot = loadDataRoot();
Bytes dataPrefix = keyPrefix.concat(DATA_PREFIX);
MerkleDataSet dataDataset = new MerkleDataSet(dataRoot, cryptoSetting, dataPrefix, exStorage, verStorage,
readonly);
this.dataDS = new MerkleDatasetAdapter(dataDataset, dataChangedListener);
}

private HashDigest loadHeaderRoot() {
byte[] hashBytes = rootDS.getValue(KEY_HEADER_ROOT);
if (hashBytes == null) {
return null;
}
return new HashDigest(hashBytes);
}

public MerkleAccount(BlockchainIdentity bcid, HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) {
this.bcid = bcid;
this.dataset = new MerkleDataSet(dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly);
private HashDigest loadDataRoot() {
byte[] hashBytes = rootDS.getValue(KEY_DATA_ROOT);
if (hashBytes == null) {
return null;
}
return new HashDigest(hashBytes);
}

/*
* (non-Javadoc)
*
* @see com.jd.blockchain.ledger.core.AccountDataSet#getAddress()
*/
@Override
public Bytes getAddress() {
return bcid.getAddress();
return accountID.getAddress();
}

/*
* (non-Javadoc)
*
* @see com.jd.blockchain.ledger.core.AccountDataSet#getPubKey()
*/
@Override
public PubKey getPubKey() {
return bcid.getPubKey();
return accountID.getPubKey();
}

@Override
public BlockchainIdentity getID() {
return accountID;
}

@Override
public VersioningMap<Bytes, BytesValue> getDataset() {
return dataDS;
}

/*
@@ -117,12 +158,22 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction
*/
@Override
public HashDigest getRootHash() {
return dataset.getRootHash();
return rootDS.getRootHash();
}

@Override
public MerkleProof getProof(Bytes key) {
return dataset.getProof(key);
public HashProof getProof(Bytes key) {
MerkleProof dataProof = dataDS.getDataset().getProof(key);
if (dataProof == null) {
return null;
}
MerkleProof rootProof = rootDS.getProof(KEY_DATA_ROOT);
if (rootProof == null) {
return null;
}
HashDegistList proof = new HashDegistList(rootProof);
proof.concat(dataProof);
return proof;
}

/**
@@ -131,90 +182,234 @@ public class MerkleAccount implements AccountHeader, MerkleProvable, Transaction
* @return
*/
public boolean isReadonly() {
return dataset.isReadonly();
return dataDS.getDataset().isReadonly();
}

/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, BytesValue value, long version) {
byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class);
return dataset.setValue(key, bytesValue, version);
public long getDataCount() {
return dataDS.getDataset().getDataCount();
}

/**
* Return the latest version entry associated the specified key; If the key
* doesn't exist, then return -1;
* 保存公钥;
*
* @param key
* @return
* @param pubKey
*/
public long getVersion(Bytes key) {
return dataset.getVersion(key);
private void savePubKey(PubKey pubKey) {
long v = headerDS.setValue(KEY_PUBKEY, TypedBytesValue.fromPubKey(pubKey), -1);
if (v < 0) {
throw new LedgerException("PubKey storage conflict!");
}
}

/**
* return the latest version's value;
* 加载公钥;
*
* @param key
* @return return null if not exist;
* @return
*/
public BytesValue getBytes(Bytes key) {
byte[] bytesValue = dataset.getValue(key);
if (bytesValue == null) {
return null;
}
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class);
private PubKey loadPubKey() {
BytesValue bytesValue = headerDS.getValue(KEY_PUBKEY);
return TypedBytesValue.wrap(bytesValue).pubKeyValue();
}

/**
* Return the specified version's value;
* 当写入新值时触发此方法;
*
* @param key
* @param version
* @return return null if not exist;
* @param value
* @param newVersion
*/
public BytesValue getBytes(Bytes key, long version) {
byte[] bytesValue = dataset.getValue(key, version);
if (bytesValue == null) {
return null;
}
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class);
protected void onUpdated(Bytes key, BytesValue value, long newVersion) {
}

@Override
public boolean isUpdated() {
return dataset.isUpdated();
return dataDS.getDataset().isUpdated() || headerDS.getDataset().isUpdated() || rootDS.isUpdated();
}

@Override
public void commit() {
dataset.commit();
dataDS.getDataset().commit();
headerDS.getDataset().commit();
rootDS.setValue(key, value, version)
baseDS.commit();
}

@Override
public void cancel() {
dataset.cancel();
baseDS.cancel();
}

private class BlockchainIdentityProxy implements BlockchainIdentity {

private Bytes address;

private PubKey pubKey;

public BlockchainIdentityProxy(Bytes address, PubKey pubKey) {
this.address = address;
this.pubKey = pubKey;
}

@Override
public Bytes getAddress() {
return address;
}

@Override
public PubKey getPubKey() {
if (pubKey == null) {
pubKey = loadPubKey();
}
return pubKey;
}

}

// ----------------------

private static class MerkleDatasetAdapter implements VersioningMap<Bytes, BytesValue> {

private static DataChangedListener NULL_LISTENER = new DataChangedListener() {
@Override
public void onChanged(Bytes key, BytesValue value, long newVersion) {
}
};

private DataChangedListener changedListener;

private MerkleDataSet dataset;

public MerkleDataSet getDataset() {
return dataset;
}

public MerkleDatasetAdapter(MerkleDataSet dataset) {
this(dataset, NULL_LISTENER);
}

public MerkleDatasetAdapter(MerkleDataSet dataset, DataChangedListener listener) {
this.dataset = dataset;
this.changedListener = listener == null ? NULL_LISTENER : listener;
}

@Override
public VersioningKVEntry<Bytes, BytesValue> getDataEntry(Bytes key) {
return new VersioningKVEntryWraper(dataset.getDataEntry(key));
}

@Override
public VersioningKVEntry<Bytes, BytesValue> getDataEntry(Bytes key, long version) {
return new VersioningKVEntryWraper(dataset.getDataEntry(key, version));
}

/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
@Override
public long setValue(Bytes key, BytesValue value, long version) {
byte[] bytesValue = BinaryProtocol.encode(value, BytesValue.class);
long v = dataset.setValue(key, bytesValue, version);
if (v > -1) {
changedListener.onChanged(key, value, v);
}
return v;
}

/**
* Return the latest version entry associated the specified key; If the key
* doesn't exist, then return -1;
*
* @param key
* @return
*/
@Override
public long getVersion(Bytes key) {
return dataset.getVersion(key);
}

/**
* return the latest version's value;
*
* @param key
* @return return null if not exist;
*/
@Override
public BytesValue getValue(Bytes key) {
byte[] bytesValue = dataset.getValue(key);
if (bytesValue == null) {
return null;
}
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class);
}

/**
* Return the specified version's value;
*
* @param key
* @param version
* @return return null if not exist;
*/
@Override
public BytesValue getValue(Bytes key, long version) {
byte[] bytesValue = dataset.getValue(key, version);
if (bytesValue == null) {
return null;
}
return BinaryProtocol.decodeAs(bytesValue, BytesValue.class);
}
}

private static interface DataChangedListener {

void onChanged(Bytes key, BytesValue value, long newVersion);

}

private static class VersioningKVEntryWraper implements VersioningKVEntry<Bytes, BytesValue> {

private VersioningKVEntry<Bytes, byte[]> kv;

public VersioningKVEntryWraper(VersioningKVEntry<Bytes, byte[]> kv) {
this.kv = kv;
}

@Override
public Bytes getKey() {
return kv.getKey();
}

@Override
public long getVersion() {
return kv.getVersion();
}

@Override
public BytesValue getValue() {
return BinaryProtocol.decodeAs(kv.getValue(), BytesValue.class);
}

}

}

+ 12
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountHeader.java View File

@@ -0,0 +1,12 @@
//package com.jd.blockchain.ledger.core;
//
//import com.jd.blockchain.binaryproto.DataField;
//import com.jd.blockchain.ledger.BlockchainIdentity;
//import com.jd.blockchain.ledger.MerkleSnapshot;
//
//public interface MerkleAccountHeader extends MerkleSnapshot {
//
// @DataField(order = 1, refContract = true)
// BlockchainIdentity getID();
//
//}

+ 62
- 128
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java View File

@@ -9,6 +9,7 @@ import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.CryptoSetting;
import com.jd.blockchain.ledger.LedgerException;
@@ -17,17 +18,24 @@ import com.jd.blockchain.ledger.MerkleSnapshot;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.RegionMap;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningMap;
public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<MerkleAccount> {
public abstract class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<MerkleAccount> {
private static final Bytes ACCOUNT_ROOT_PREFIX = Bytes.fromString("ROOT/");
static {
DataContractRegistry.register(MerkleSnapshot.class);
DataContractRegistry.register(AccountHeader.class);
}
private final String keyPrefix;
private final Bytes keyPrefix;
/**
* 账户根哈希的数据集;
*/
private MerkleDataSet merkleDataset;
/**
@@ -36,7 +44,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
*
*/
// TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题;
private Map<Bytes, InnerVersioningAccount> latestAccountsCache = new HashMap<>();
private Map<Bytes, InnerMerkleAccount> latestAccountsCache = new HashMap<>();
private ExPolicyKVStorage baseExStorage;
@@ -44,7 +52,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
private CryptoSetting cryptoSetting;
private boolean updated;
private volatile boolean updated;
private AccountAccessPolicy accessPolicy;
@@ -56,12 +64,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
merkleDataset.setReadonly();
}
public MerkleAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage,
public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage,
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) {
this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy);
}
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix,
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly,
AccountAccessPolicy accessPolicy) {
this.keyPrefix = keyPrefix;
@@ -70,6 +78,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
this.baseVerStorage = verStorage;
this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage,
this.baseVerStorage, readonly);
this.accessPolicy = accessPolicy;
}
@@ -83,10 +92,11 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
return merkleDataset.getProof(key);
}
public AccountHeader[] getHeaders(int fromIndex, int count) {
@Override
public BlockchainIdentity[] getHeaders(int fromIndex, int count) {
byte[][] results = merkleDataset.getLatestValues(fromIndex, count);
AccountHeader[] accounts = new AccountHeader[results.length];
BlockchainIdentity[] accounts = new BlockchainIdentity[results.length];
for (int i = 0; i < results.length; i++) {
accounts[i] = deserialize(results[i]);
}
@@ -104,8 +114,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
// keyPrefix, baseExStorage, baseVerStorage, true, accessPolicy, accInfo.);
// }
private AccountHeader deserialize(byte[] txBytes) {
return BinaryProtocol.decode(txBytes);
private BlockchainIdentity deserialize(byte[] txBytes) {
return BinaryProtocol.decodeAs(txBytes, BlockchainIdentity.class);
}
/**
@@ -128,6 +138,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
* @param address
* @return
*/
@Override
public MerkleAccount getAccount(Bytes address) {
return this.getAccount(address, -1);
}
@@ -157,7 +168,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
* @return
*/
public long getVersion(Bytes address) {
InnerVersioningAccount acc = latestAccountsCache.get(address);
InnerMerkleAccount acc = latestAccountsCache.get(address);
if (acc != null) {
// 已注册尚未提交,也返回 -1;
return acc.version == -1 ? 0 : acc.version;
@@ -177,7 +188,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
*/
public MerkleAccount getAccount(Bytes address, long version) {
version = version < 0 ? -1 : version;
InnerVersioningAccount acc = latestAccountsCache.get(address);
InnerMerkleAccount acc = latestAccountsCache.get(address);
if (acc != null && version == -1) {
return acc;
} else if (acc != null && acc.version == version) {
@@ -218,8 +229,9 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
// ExPolicyKVStorage ss = PrefixAppender.prefix(prefix, baseExStorage);
// VersioningKVStorage vs = PrefixAppender.prefix(prefix, baseVerStorage);
// BaseAccount accDS = deserialize(bytes, cryptoSetting, ss, vs, readonly);
String prefix = keyPrefix + address;
acc = deserialize(bytes, cryptoSetting, prefix, baseExStorage, baseVerStorage, readonly, latestVersion);
Bytes prefix = keyPrefix.concat(address);
acc = deserialize(bytes, cryptoSetting, prefix, readonly, latestVersion);
if (!readonly) {
// cache the latest version witch enable reading and writing;
// readonly version of account not necessary to be cached;
@@ -239,14 +251,16 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
* @param pubKey 公钥;
* @return 注册成功的账户对象;
*/
public MerkleAccount register(Bytes address, PubKey pubKey) {
public MerkleAccount register(BlockchainIdentity accountId) {
if (isReadonly()) {
throw new IllegalArgumentException("This AccountSet is readonly!");
}
Bytes address = accountId.getAddress();
PubKey pubKey = accountId.getPubKey();
verifyAddressEncoding(address, pubKey);
InnerVersioningAccount cachedAcc = latestAccountsCache.get(address);
InnerMerkleAccount cachedAcc = latestAccountsCache.get(address);
if (cachedAcc != null) {
if (cachedAcc.version < 0) {
// 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化;
@@ -272,9 +286,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
// BaseAccount accDS = createInstance(address, pubKey, cryptoSetting,
// accExStorage, accVerStorage);
String prefix = keyPrefix + address;
InnerVersioningAccount acc = createInstance(address, pubKey, cryptoSetting, prefix, baseExStorage, baseVerStorage,
-1);
Bytes prefix = keyPrefix.concat(address);
InnerMerkleAccount acc = createInstance(accountId, cryptoSetting, prefix, -1);
latestAccountsCache.put(address, acc);
updated = true;
@@ -288,20 +301,24 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
}
}
private InnerVersioningAccount createInstance(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting,
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) {
return new InnerVersioningAccount(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage, version);
private InnerMerkleAccount createInstance(BlockchainIdentity header, CryptoSetting cryptoSetting, Bytes keyPrefix,
long version) {
return new InnerMerkleAccount(header, version, cryptoSetting, keyPrefix, baseExStorage, baseVerStorage);
}
private InnerVersioningAccount deserialize(byte[] bytes, CryptoSetting cryptoSetting, String keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, long version) {
AccountHeader accInfo = BinaryProtocol.decode(bytes);
return new InnerVersioningAccount(accInfo.getAddress(), accInfo.getPubKey(), accInfo.getRootHash(), cryptoSetting,
keyPrefix, exStorage, verStorage, readonly, version);
private InnerMerkleAccount deserialize(byte[] bytes, CryptoSetting cryptoSetting, Bytes keyPrefix, boolean readonly,
long version) {
BlockchainIdentity id = BinaryProtocol.decodeAs(bytes, BlockchainIdentity.class);
return new InnerMerkleAccount(header.getID(), version, header.getRootHash(), cryptoSetting, keyPrefix,
baseExStorage, baseVerStorage, readonly);
}
private byte[] serialize(AccountHeader account) {
return BinaryProtocol.encode(account, AccountHeader.class);
// TODO: 优化:区块链身份(地址+公钥)与其 Merkle
// 树根哈希分开独立存储;不必作为一个整块,避免状态数据写入时频繁重写公钥,尤其某些算法的公钥可能很大;
private byte[] serialize(MerkleAccountHeader account) {
return BinaryProtocol.encode(account, MerkleAccountHeader.class);
}
@Override
@@ -315,16 +332,17 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
return;
}
try {
for (InnerVersioningAccount acc : latestAccountsCache.values()) {
for (InnerMerkleAccount acc : latestAccountsCache.values()) {
// updated or new created;
if (acc.isUpdated() || acc.version < 0) {
// 提交更改,更新哈希;
acc.commit();
byte[] value = serialize(acc);
long ver = merkleDataset.setValue(acc.getAddress(), value, acc.version);
long ver = merkleDataset.setValue(acc.getID().getAddress(), value, acc.version);
if (ver < 0) {
// Update fail;
throw new LedgerException("Account updating fail! --[Address=" + acc.getAddress() + "]");
throw new LedgerException(
"Account updating fail! --[Address=" + acc.getID().getAddress() + "]");
}
}
}
@@ -343,7 +361,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
Bytes[] addresses = new Bytes[latestAccountsCache.size()];
latestAccountsCache.keySet().toArray(addresses);
for (Bytes address : addresses) {
InnerVersioningAccount acc = latestAccountsCache.remove(address);
InnerMerkleAccount acc = latestAccountsCache.remove(address);
// cancel;
if (acc.isUpdated()) {
acc.cancel();
@@ -352,108 +370,24 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ
updated = false;
}
public static class AccountHeaderData implements AccountHeader {
private Bytes address;
private PubKey pubKey;
private HashDigest rootHash;
public AccountHeaderData(Bytes address, PubKey pubKey, HashDigest rootHash) {
this.address = address;
this.pubKey = pubKey;
this.rootHash = rootHash;
}
private class InnerMerkleAccount extends MerkleAccount {
@Override
public Bytes getAddress() {
return address;
public InnerMerkleAccount(BlockchainIdentity accountID, long version, CryptoSetting cryptoSetting,
Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) {
super(accountID, version, cryptoSetting, keyPrefix, exStorage, verStorage);
}
@Override
public PubKey getPubKey() {
return pubKey;
public InnerMerkleAccount(BlockchainIdentity accountID, long version, HashDigest dataRootHash,
CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage,
VersioningKVStorage verStorage, boolean readonly) {
super(accountID, version, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly);
}
@Override
public HashDigest getRootHash() {
return rootHash;
protected void onUpdated(Bytes key, BytesValue value, long newVersion) {
updated = true;
}
}
private class InnerVersioningAccount extends MerkleAccount {
// private final BaseAccount account;
private final long version;
// public VersioningAccount(BaseAccount account, long version) {
// this.account = account;
// this.version = version;
// }
public InnerVersioningAccount(Bytes address, PubKey pubKey, HashDigest rootHash, CryptoSetting cryptoSetting,
String keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly,
long version) {
super(address, pubKey, rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly);
this.version = version;
}
public InnerVersioningAccount(Bytes address, PubKey pubKey, CryptoSetting cryptoSetting, String keyPrefix,
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, long version) {
super(address, pubKey, cryptoSetting, keyPrefix, exStorage, verStorage);
this.version = version;
}
// @Override
// public Bytes getAddress() {
// return account.getAddress();
// }
//
// @Override
// public PubKey getPubKey() {
// return account.getPubKey();
// }
//
// @Override
// public HashDigest getRootHash() {
// return account.getRootHash();
// }
//
// @Override
// public MerkleProof getProof(Bytes key) {
// return account.getProof(key);
// }
//
// @Override
// public boolean isReadonly() {
// return account.isReadonly();
// }
@Override
public long setBytes(Bytes key, BytesValue value, long version) {
long v = super.setBytes(key, value, version);
if (v > -1) {
updated = true;
}
return v;
}
// @Override
// public long getKeyVersion(Bytes key) {
// return account.getKeyVersion(key);
// }
//
// @Override
// public byte[] getBytes(Bytes key) {
// return account.getBytes(key);
// }
//
// @Override
// public byte[] getBytes(Bytes key, long version) {
// return account.getBytes(key, version);
// }
}
}

+ 3
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataEntry.java View File

@@ -1,11 +1,12 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;

public interface MerkleDataEntry {
VersioningKVEntry getData();
VersioningKVEntry<Bytes, byte[]> getData();
MerkleProof getProof();
}

+ 96
- 81
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java View File

@@ -7,12 +7,13 @@ import com.jd.blockchain.ledger.MerkleDataNode;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.storage.service.utils.BufferedKVStorage;
import com.jd.blockchain.storage.service.utils.VersioningKVData;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.VersioningMap;
import com.jd.blockchain.utils.io.BytesUtils;
/**
@@ -23,7 +24,7 @@ import com.jd.blockchain.utils.io.BytesUtils;
* @author huanghaiquan
*
*/
public class MerkleDataSet implements Transactional, MerkleProvable {
public class MerkleDataSet implements Transactional, MerkleProvable, VersioningMap<Bytes, byte[]> {
/**
* 4 MB MaxSize of value;
@@ -32,9 +33,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
public static final String ORIG_KEY_SEPERATOR = LedgerConsts.KEY_SEPERATOR;
public static final String SN_PREFIX = "SN" + ORIG_KEY_SEPERATOR;
public static final String DATA_PREFIX = "KV" + ORIG_KEY_SEPERATOR;
public static final String MERKLE_TREE_PREFIX = "MKL" + ORIG_KEY_SEPERATOR;
public static final Bytes SN_PREFIX = Bytes.fromString("SN" + ORIG_KEY_SEPERATOR);
public static final Bytes DATA_PREFIX = Bytes.fromString("KV" + ORIG_KEY_SEPERATOR);
public static final Bytes MERKLE_TREE_PREFIX = Bytes.fromString("MKL" + ORIG_KEY_SEPERATOR);
private final Bytes snKeyPrefix;
private final Bytes dataKeyPrefix;
@@ -102,19 +103,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
* @param merkleTreeStorage
* @param snGenerator
*/
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, String keyPrefix,
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, Bytes keyPrefix,
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) {
// 缓冲对KV的写入;
this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false);
// 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击;
snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX);
dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX);
// snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX);
// dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX);
snKeyPrefix = keyPrefix.concat(SN_PREFIX);
dataKeyPrefix = keyPrefix.concat(DATA_PREFIX);
this.valueStorage = bufferedStorage;
this.snStorage = bufferedStorage;
// MerkleTree 本身是可缓冲的;
merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX);
merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX);
ExPolicyKVStorage merkleTreeStorage = exPolicyStorage;
this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly);
@@ -154,20 +157,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
return values;
}
public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) {
public VersioningKVEntry<Bytes, byte[]>[] getLatestDataEntries(int fromIndex, int count) {
if (count > LedgerConsts.MAX_LIST_COUNT) {
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!");
}
if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) {
throw new IllegalArgumentException("Index out of bound!");
}
VersioningKVEntry[] values = new VersioningKVEntry[count];
@SuppressWarnings("unchecked")
VersioningKVEntry<Bytes, byte[]>[] values = new VersioningKVEntry[count];
byte[] bytesValue;
for (int i = 0; i < count; i++) {
MerkleDataNode dataNode = merkleTree.getData(fromIndex + i);
Bytes dataKey = encodeDataKey(dataNode.getKey());
bytesValue = valueStorage.get(dataKey, dataNode.getVersion());
values[i] = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), bytesValue);
values[i] = new VersioningKVData<Bytes, byte[]>(dataNode.getKey(), dataNode.getVersion(), bytesValue);
}
return values;
}
@@ -192,32 +196,34 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
*/
public String getKeyAtIndex(int fromIndex) {
MerkleDataNode dataNode = merkleTree.getData(fromIndex);
return dataNode.getKey().toUTF8String();
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, it will be created when the version arg was -1.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected latest version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setValue(String key, byte[] value, long version) {
return setValue(Bytes.fromString(key), value, version);
}
//TODO: 未去掉前缀;
return dataNode.getKey().toUTF8String();
}
// /**
// * Create or update the value associated the specified key if the version
// * checking is passed.<br>
// *
// * The value of the key will be updated only if it's latest version equals the
// * specified version argument. <br>
// * If the key doesn't exist, it will be created when the version arg was -1.
// * <p>
// * If updating is performed, the version of the key increase by 1. <br>
// * If creating is performed, the version of the key initialize by 0. <br>
// *
// * @param key The key of data;
// * @param value The value of data;
// * @param version The expected latest version of the key.
// * @return The new version of the key. <br>
// * If the key is new created success, then return 0; <br>
// * If the key is updated success, then return the new version;<br>
// * If this operation fail by version checking or other reason, then
// * return -1;
// */
// @Override
// public long setValue(String key, byte[] value, long version) {
// return setValue(Bytes.fromString(key), value, version);
// }
/**
* Create or update the value associated the specified key if the version
@@ -239,6 +245,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
* If this operation fail by version checking or other reason, then
* return -1;
*/
@Override
public long setValue(Bytes key, byte[] value, long version) {
if (readonly) {
throw new IllegalArgumentException("This merkle dataset is readonly!");
@@ -336,18 +343,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
return mdn.getVersion();
}
/**
* Return the specified version's value;<br>
*
* If the key with the specified version doesn't exist, then return null;<br>
* If the version is specified to -1, then return the latest version's value;
*
* @param key
* @param version
*/
public byte[] getValue(String key, long version) {
return getValue(Bytes.fromString(key), version);
}
// /**
// * Return the specified version's value;<br>
// *
// * If the key with the specified version doesn't exist, then return null;<br>
// * If the version is specified to -1, then return the latest version's value;
// *
// * @param key
// * @param version
// */
// @Override
// public byte[] getValue(String key, long version) {
// return getValue(Bytes.fromString(key), version);
// }
/**
* Return the specified version's value;<br>
@@ -358,6 +366,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
* @param key
* @param version
*/
@Override
public byte[] getValue(Bytes key, long version) {
long latestVersion = getMerkleVersion(key);
if (latestVersion < 0 || version > latestVersion) {
@@ -370,15 +379,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
return valueStorage.get(dataKey, version);
}
/**
* Return the latest version's value;
*
* @param key
* @return return null if not exist;
*/
public byte[] getValue(String key) {
return getValue(Bytes.fromString(key));
}
// /**
// * Return the latest version's value;
// *
// * @param key
// * @return return null if not exist;
// */
// @Override
// public byte[] getValue(String key) {
// return getValue(Bytes.fromString(key));
// }
/**
* Return the latest version's value;
@@ -386,6 +396,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
* @param key
* @return return null if not exist;
*/
@Override
public byte[] getValue(Bytes key) {
long latestVersion = getMerkleVersion(key);
if (latestVersion < 0) {
@@ -395,16 +406,17 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
return valueStorage.get(dataKey, latestVersion);
}
/**
* Return the latest version entry associated the specified key; If the key
* doesn't exist, then return -1;
*
* @param key
* @return
*/
public long getVersion(String key) {
return getMerkleVersion(Bytes.fromString(key));
}
// /**
// * Return the latest version entry associated the specified key; If the key
// * doesn't exist, then return -1;
// *
// * @param key
// * @return
// */
// @Override
// public long getVersion(String key) {
// return getMerkleVersion(Bytes.fromString(key));
// }
/**
* Return the latest version entry associated the specified key; If the key
@@ -413,20 +425,22 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
* @param key
* @return
*/
@Override
public long getVersion(Bytes key) {
return getMerkleVersion(key);
}
public VersioningKVEntry getDataEntry(String key) {
return getDataEntry(Bytes.fromString(key));
}
// public VersioningKVEntry getDataEntry(String key) {
// return getDataEntry(Bytes.fromString(key));
// }
/**
*
* @param key
* @return Null if the key doesn't exist!
*/
public VersioningKVEntry getDataEntry(Bytes key) {
@Override
public VersioningKVEntry<Bytes, byte[]> getDataEntry(Bytes key) {
long latestVersion = getMerkleVersion(key);
if (latestVersion < 0) {
return null;
@@ -436,10 +450,11 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
if (value == null) {
return null;
}
return new VersioningKVData(key, latestVersion, value);
return new VersioningKVData<Bytes, byte[]>(key, latestVersion, value);
}
public VersioningKVEntry getDataEntry(Bytes key, long version) {
@Override
public VersioningKVEntry<Bytes, byte[]> getDataEntry(Bytes key, long version) {
long latestVersion = getMerkleVersion(key);
if (latestVersion < 0 || version > latestVersion) {
// key not exist, or the specified version is out of the latest version indexed
@@ -452,11 +467,11 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
if (value == null) {
return null;
}
return new VersioningKVData(key, version, value);
return new VersioningKVData<Bytes, byte[]>(key, version, value);
}
public MerkleDataEntry getMerkleEntry(Bytes key, long version) {
VersioningKVEntry dataEntry = getDataEntry(key, version);
VersioningKVEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version);
if (dataEntry == null) {
return null;
}
@@ -465,7 +480,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
}
public MerkleDataEntry getMerkleEntry(Bytes key) {
VersioningKVEntry dataEntry = getDataEntry(key);
VersioningKVEntry<Bytes, byte[]> dataEntry = getDataEntry(key);
if (dataEntry == null) {
return null;
}
@@ -499,16 +514,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
*/
private static class MerkleDataEntryWrapper implements MerkleDataEntry {
private VersioningKVEntry data;
private VersioningKVEntry<Bytes, byte[]> data;
private MerkleProof proof;
public MerkleDataEntryWrapper(VersioningKVEntry data, MerkleProof proof) {
public MerkleDataEntryWrapper(VersioningKVEntry<Bytes, byte[]> data, MerkleProof proof) {
this.data = data;
this.proof = proof;
}
@Override
public VersioningKVEntry getData() {
public VersioningKVEntry<Bytes, byte[]> getData() {
return data;
}


+ 1
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java View File

@@ -14,10 +14,10 @@ import com.jd.blockchain.ledger.RolePrivileges;
import com.jd.blockchain.ledger.TransactionPermission;
import com.jd.blockchain.ledger.TransactionPrivilege;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningKVEntry;

public class RolePrivilegeDataset implements Transactional, MerkleProvable, RolePrivilegeSettings {



+ 7
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/StringKeyMap.java View File

@@ -0,0 +1,7 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.utils.VersioningMap;

public interface StringKeyMap<V> extends VersioningMap<String, V> {

}

+ 12
- 26
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java View File

@@ -2,10 +2,11 @@ package com.jd.blockchain.ledger.core;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.UserInfo;
import com.jd.blockchain.ledger.UserAccountHeader;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningMap;
/**
* 用户账户;
@@ -13,35 +14,20 @@ import com.jd.blockchain.utils.Bytes;
* @author huanghaiquan
*
*/
public class UserAccount implements UserInfo {
public class UserAccount extends MerkleAccount{ //implements UserInfo {
private static final Bytes USER_INFO_PREFIX = Bytes.fromString("PROP" + LedgerConsts.KEY_SEPERATOR);
private static final Bytes DATA_PUB_KEY = Bytes.fromString("DATA-PUBKEY");
private MerkleAccount baseAccount;
// private MerkleAccount baseAccount;
@Override
public Bytes getAddress() {
return baseAccount.getAddress();
}
@Override
public PubKey getPubKey() {
return baseAccount.getPubKey();
}
@Override
public HashDigest getRootHash() {
return baseAccount.getRootHash();
}
public UserAccount(MerkleAccount baseAccount) {
public UserAccount(VersioningMap baseAccount) {
this.baseAccount = baseAccount;
}
public PubKey getDataPubKey() {
BytesValue pkBytes = baseAccount.getBytes(DATA_PUB_KEY);
BytesValue pkBytes = baseAccount.getValue(DATA_PUB_KEY);
if (pkBytes == null) {
return null;
}
@@ -50,12 +36,12 @@ public class UserAccount implements UserInfo {
public long setDataPubKey(PubKey pubKey) {
byte[] pkBytes = pubKey.toBytes();
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1);
return baseAccount.setValue(DATA_PUB_KEY, TypedBytesValue.fromBytes(pkBytes), -1);
}
public long setDataPubKey(PubKey pubKey, long version) {
byte[] pkBytes = pubKey.toBytes();
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version);
return baseAccount.setValue(DATA_PUB_KEY, TypedBytesValue.fromBytes(pkBytes), version);
}
public long setProperty(String key, String value, long version) {
@@ -63,16 +49,16 @@ public class UserAccount implements UserInfo {
}
public long setProperty(Bytes key, String value, long version) {
return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version);
return baseAccount.setValue(encodePropertyKey(key), TypedBytesValue.fromText(value), version);
}
public String getProperty(Bytes key) {
BytesValue value = baseAccount.getBytes(encodePropertyKey(key));
BytesValue value = baseAccount.getValue(encodePropertyKey(key));
return value == null ? null : value.getValue().toUTF8String();
}
public String getProperty(Bytes key, long version) {
BytesValue value = baseAccount.getBytes(encodePropertyKey(key), version);
BytesValue value = baseAccount.getValue(encodePropertyKey(key), version);
return value == null ? null : value.getValue().toUTF8String();
}


+ 4
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccountSet.java View File

@@ -10,6 +10,7 @@ import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningMap;
/**
* @author huanghaiquan
@@ -71,7 +72,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery {
@Override
public UserAccount getAccount(Bytes address) {
MerkleAccount baseAccount = accountSet.getAccount(address);
VersioningMap baseAccount = accountSet.getAccount(address);
return new UserAccount(baseAccount);
}
@@ -82,7 +83,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery {
@Override
public UserAccount getAccount(Bytes address, long version) {
MerkleAccount baseAccount = accountSet.getAccount(address, version);
VersioningMap baseAccount = accountSet.getAccount(address, version);
return new UserAccount(baseAccount);
}
@@ -100,7 +101,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery {
* @return 注册成功的用户对象;
*/
public UserAccount register(Bytes address, PubKey pubKey) {
MerkleAccount baseAccount = accountSet.register(address, pubKey);
VersioningMap baseAccount = accountSet.register(address, pubKey);
return new UserAccount(baseAccount);
}


+ 1
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRoleDataset.java View File

@@ -13,10 +13,10 @@ import com.jd.blockchain.ledger.RolesPolicy;
import com.jd.blockchain.ledger.UserRoles;
import com.jd.blockchain.ledger.UserAuthorizationSettings;
import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningKVEntry;

/**
* User-Role authorization data set;


+ 8
- 8
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java View File

@@ -268,7 +268,7 @@ public class ContractLedgerContext implements LedgerContext {

@Override
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromText(value);
BytesValue bytesValue = TypedBytesValue.fromText(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -276,7 +276,7 @@ public class ContractLedgerContext implements LedgerContext {

@Override
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) {
BytesValue bytesValue = BytesData.fromBytes(value);
BytesValue bytesValue = TypedBytesValue.fromBytes(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -284,7 +284,7 @@ public class ContractLedgerContext implements LedgerContext {

@Override
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) {
BytesValue bytesValue = BytesData.fromInt64(value);
BytesValue bytesValue = TypedBytesValue.fromInt64(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -301,7 +301,7 @@ public class ContractLedgerContext implements LedgerContext {
@Override
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromJSON(value);
BytesValue bytesValue = TypedBytesValue.fromJSON(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -309,7 +309,7 @@ public class ContractLedgerContext implements LedgerContext {
@Override
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromXML(value);
BytesValue bytesValue = TypedBytesValue.fromXML(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -317,7 +317,7 @@ public class ContractLedgerContext implements LedgerContext {
@Override
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) {
BytesValue bytesValue = BytesData.fromBytes(value);
BytesValue bytesValue = TypedBytesValue.fromBytes(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -325,7 +325,7 @@ public class ContractLedgerContext implements LedgerContext {
@Override
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) {
BytesValue bytesValue = BytesData.fromImage(value);
BytesValue bytesValue = TypedBytesValue.fromImage(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;
@@ -333,7 +333,7 @@ public class ContractLedgerContext implements LedgerContext {
@Override
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) {
BytesValue bytesValue = BytesData.fromTimestamp(value);
BytesValue bytesValue = TypedBytesValue.fromTimestamp(value);
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
handle(op);
return this;


+ 7
- 7
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BaseAccountTest.java View File

@@ -12,7 +12,7 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.core.MerkleAccount;
import com.jd.blockchain.ledger.core.CryptoConfig;
import com.jd.blockchain.storage.service.utils.MemoryKVStorage;
@@ -53,33 +53,33 @@ public class BaseAccountTest {
assertFalse(baseAccount.isReadonly());

// 在空白状态下写入数据;
long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0);
long v = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A"), 0);
// 预期失败;
assertEquals(-1, v);

v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1);
v = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A"), 1);
// 预期失败;
assertEquals(-1, v);

v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1);
v = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A"), -1);
// 预期成功;
assertEquals(0, v);

v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1);
v = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A-1"), -1);
// 已经存在版本,指定版本号-1,预期导致失败;
assertEquals(-1, v);

baseAccount.commit();
v = 0;
for (int i = 0; i < 10; i++) {
long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v);
long s = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A_" + i), v);
baseAccount.commit();
// 预期成功;
assertEquals(v + 1, s);
v++;
}

v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1);
v = baseAccount.setValue(Bytes.fromString("A"), TypedBytesValue.fromText("VALUE_A_" + v), v + 1);
// 预期成功;
assertEquals(-1, v);



+ 2
- 2
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java View File

@@ -132,7 +132,7 @@ public class ContractInvokingTest {
assertEquals(1, opResults.length);
assertEquals(0, opResults[0].getIndex());

byte[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class);
byte[] expectedRetnBytes = BinaryProtocol.encode(TypedBytesValue.fromInt64(issueAmount), BytesValue.class);
byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class);
assertArrayEquals(expectedRetnBytes, reallyRetnBytes);

@@ -218,7 +218,7 @@ public class ContractInvokingTest {
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare();
txResultHandle.commit();

BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getBytes(key,
BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getValue(key,
-1);
System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getValue().toUTF8String());



+ 1
- 1
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleDataSetTest.java View File

@@ -23,9 +23,9 @@ import com.jd.blockchain.crypto.service.sm.SMCryptoService;
import com.jd.blockchain.ledger.MerkleProof;
import com.jd.blockchain.ledger.core.CryptoConfig;
import com.jd.blockchain.ledger.core.MerkleDataSet;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.utils.MemoryKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.io.BytesUtils;

public class MerkleDataSetTest {


+ 6
- 6
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java View File

@@ -332,13 +332,13 @@ public class TransactionBatchProcessorTest {
newBlock = newBlockEditor.prepare();
newBlockEditor.commit();

BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1",
BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K1",
0);
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1",
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K1",
1);
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K2",
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K2",
0);
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3",
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K3",
0);

assertNotNull(v1_0);
@@ -376,8 +376,8 @@ public class TransactionBatchProcessorTest {
newBlock = newBlockEditor.prepare();
newBlockEditor.commit();

BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1");
v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3");
BytesValue v1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K1");
v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K3");

// k1 的版本仍然为1,没有更新;
long k1_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress())


+ 1
- 1
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AccountHeader.java View File

@@ -8,7 +8,7 @@ import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.utils.Bytes;

@DataContract(code= DataCodes.ACCOUNT_HEADER)
public interface AccountHeader extends MerkleSnapshot{
public interface AccountHeader { //extends MerkleSnapshot{
@DataField(order=1, primitiveType = PrimitiveType.BYTES)
Bytes getAddress();


+ 0
- 118
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java View File

@@ -1,118 +0,0 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.io.BytesUtils;

/**
*
* @author huanghaiquan
*
*/
public class BytesData implements BytesValue {
DataType type;
Bytes value;

private BytesData(DataType type, byte[] bytes) {
this.type = type;
this.value = new Bytes(bytes);
}

private BytesData(DataType type, Bytes bytes) {
this.type = type;
this.value = bytes;
}
public static BytesValue fromType(DataType type, byte[] value) {
return new BytesData(type, value);
}

public static BytesValue fromBytes(byte[] value) {
return new BytesData(DataType.BYTES, value);
}

public static BytesValue fromBytes(Bytes value) {
return new BytesData(DataType.BYTES, value);
}

public static BytesValue fromImage(byte[] value) {
return new BytesData(DataType.IMG, value);
}

public static BytesValue fromImage(Bytes value) {
return new BytesData(DataType.IMG, value);
}

/**
* 以 UTF-8 编码从字符串转换为字节数组值;
*
* @param value
* @return
*/
public static BytesValue fromText(String value) {
return new BytesData(DataType.TEXT, BytesUtils.toBytes(value));
}

/**
* 以 UTF-8 编码把字节数组值转换为字符串;
*
* @param bytesValue
* @return
*/
public static String toText(BytesValue bytesValue) {
if (bytesValue == null) {
return null;
}
if (bytesValue.getType() != DataType.TEXT) {
throw new ValueTypeCastException("The expected value type is " + DataType.TEXT.toString()
+ ", but it is actually " + bytesValue.getType().toString() + "!");
}
return bytesValue.getValue().toUTF8String();
}

public static BytesValue fromJSON(String value) {
return new BytesData(DataType.JSON, BytesUtils.toBytes(value));
}

public static BytesValue fromXML(String value) {
return new BytesData(DataType.XML, BytesUtils.toBytes(value));
}

public static BytesValue fromInt32(int value) {
return new BytesData(DataType.INT32, BytesUtils.toBytes(value));
}

public static BytesValue fromInt64(long value) {
return new BytesData(DataType.INT64, BytesUtils.toBytes(value));
}

public static BytesValue fromInt16(short value) {
return new BytesData(DataType.INT16, BytesUtils.toBytes(value));
}

public static BytesValue fromInt8(byte value) {
return new BytesData(DataType.INT8, BytesUtils.toBytes(value));
}

public static BytesValue fromTimestamp(long value) {
return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value));
}

public static BytesValue fromBoolean(boolean value) {
return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value));
}

@Override
public DataType getType() {
return this.type;
}

public void setType(DataType type) {
this.type = type;
}

@Override
public Bytes getValue() {
return this.value;
}

}

+ 4
- 4
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java View File

@@ -14,18 +14,18 @@ public class BytesDataList implements BytesValueList {
}

public static BytesValueList singleText(String value) {
return new BytesDataList(BytesData.fromText(value));
return new BytesDataList(TypedBytesValue.fromText(value));
}
public static BytesValueList singleLong(long value) {
return new BytesDataList(BytesData.fromInt64(value));
return new BytesDataList(TypedBytesValue.fromInt64(value));
}
public static BytesValueList singleInt(int value) {
return new BytesDataList(BytesData.fromInt32(value));
return new BytesDataList(TypedBytesValue.fromInt32(value));
}
public static BytesValueList singleBoolean(boolean value) {
return new BytesDataList(BytesData.fromBoolean(value));
return new BytesDataList(TypedBytesValue.fromBoolean(value));
}
}

+ 1
- 1
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java View File

@@ -68,7 +68,7 @@ public class BytesValueEncoding {
}
// 将对象序列化
byte[] serialBytes = BinaryProtocol.encode(value, type);
return BytesData.fromType(DataType.DATA_CONTRACT, serialBytes);
return TypedBytesValue.fromType(DataType.DATA_CONTRACT, serialBytes);
}
BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type);
if (bytesValueResolver == null) {


+ 59
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java View File

@@ -106,6 +106,20 @@ public enum DataType {
* DataContract 数据;
*/
DATA_CONTRACT((byte) (BaseType.EXT | 0x01));
public static final boolean BOOLEAN_DEFAULT_VALUE = false;
public static final byte INT8_DEFAULT_VALUE = 0;
public static final short INT16_DEFAULT_VALUE = 0;
public static final int INT32_DEFAULT_VALUE = 0;
public static final long INT64_DEFAULT_VALUE = 0;
@EnumField(type = PrimitiveType.INT8)
public final byte CODE;
@@ -114,6 +128,51 @@ public enum DataType {
this.CODE = code;
}
/**
* 是否表示“文本类型”或“文本衍生类型”;
*
* @return
*/
public boolean isText() {
return BaseType.TEXT == (BaseType.TEXT & CODE);
}
/**
* 是否表示“字节类型”或“字节衍生类型”;
*
* @return
*/
public boolean isBytes() {
return BaseType.BYTES == (BaseType.BYTES & CODE);
}
/**
* 是否表示“整数类型”或“整数衍生类型”;
*
* @return
*/
public boolean isInteger() {
return BaseType.INTEGER == (BaseType.INTEGER & CODE);
}
/**
* 是否表示“布尔类型”;
*
* @return
*/
public boolean isBoolean() {
return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE);
}
/**
* 是否表示“扩展类型”;
*
* @return
*/
public boolean isExt() {
return BaseType.EXT == (BaseType.EXT & CODE);
}
public static DataType valueOf(byte code) {
for (DataType dataType : DataType.values()) {
if (dataType.CODE == code) {


+ 44
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/HashProof.java View File

@@ -0,0 +1,44 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.crypto.HashDigest;

public interface HashProof {
/**
* 最大层级数; <br>
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级;
*
* @return
*
* @see MerkleTree#getLevel()
*/
int getLevels();

/**
* 返回证明中指定层级的节点的哈希;
* <p>
*
* @param level
* 参数值为 0 返回的是数据节点的哈希; <br>
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希;
* @return
*/
HashDigest getHash(int level);
/**
* 返回根节点的哈希;
*
* @return
*/
default HashDigest getRootHash() {
return getHash(getLevels());
}

/**
* 返回数据节点的哈希;
*
* @return
*/
default HashDigest getDataHash() {
return getHash(0);
}
}

+ 29
- 47
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/MerkleProof.java View File

@@ -1,8 +1,6 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.crypto.HashDigest;

public interface MerkleProof {
public interface MerkleProof extends HashProof {

/**
* 所证明的数据节点的序列号;
@@ -11,62 +9,46 @@ public interface MerkleProof {
*/
long getSN();

/**
* 最大层级数; <br>
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级;
*
* @return
*
* @see MerkleTree#getLevel()
*/
int getLevels();

/**
* 返回证明中指定层级的节点的哈希;
* <p>
*
* @param level
* 参数值为 0 返回的是数据节点的哈希; <br>
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希;
* @return
*/
HashDigest getHash(int level);
MerkleNode getNode(int level);

// /**
// * 返回证明中指定层级的数据起始序号;
// * 最大层级数; <br>
// * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级;
// *
// * @param level
// * @return
// *
// * @see MerkleTree#getLevel()
// */
// long getStartingSN(int level);
// int getLevels();
//
// /**
// * 返回证明中指定层级的数据记录总数;
// * 返回证明中指定层级的节点的哈希;
// * <p>
// *
// * @param level
// * 参数值为 0 返回的是数据节点的哈希; <br>
// * 参数值为 {@link #getLevels()} 返回的是根节点的哈希;
// * @return
// */
// long getDataCount(int level);
// HashDigest getHash(int level);

/**
* 返回根节点的哈希;
*
* @return
*/
default HashDigest getRootHash() {
return getHash(getLevels());
}
MerkleNode getNode(int level);

/**
* 返回数据节点的哈希;
*
* @return
*/
default HashDigest getDataHash() {
return getHash(0);
}
// * 返回根节点的哈希;
// *
// * @return
// */
// default HashDigest getRootHash() {
// return getHash(getLevels());
// }
//
// /**
// * 返回数据节点的哈希;
// *
// * @return
// */
// default HashDigest getDataHash() {
// return getHash(0);
// }
default MerkleDataNode getDataNode() {
return (MerkleDataNode)getNode(0);


+ 455
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedBytesValue.java View File

@@ -0,0 +1,455 @@
package com.jd.blockchain.ledger;

import java.math.BigInteger;
import java.util.Date;

import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.crypto.SignatureDigest;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.io.BytesUtils;

/**
*
* @author huanghaiquan
*
*/
public class TypedBytesValue implements BytesValue {
public static final BytesValue NIL = new TypedBytesValue();
private DataType type;
private Bytes value;

private TypedBytesValue(DataType type, byte[] bytes) {
this.type = type;
this.value = new Bytes(bytes);
}

private TypedBytesValue(DataType type, Bytes bytes) {
this.type = type;
this.value = bytes;
}
private TypedBytesValue(BytesValue bytesValue) {
this.type = bytesValue.getType();
this.value = bytesValue.getValue();
}
private TypedBytesValue() {
this.type = DataType.NIL;
}

@Override
public DataType getType() {
return this.type;
}

@Override
public Bytes getValue() {
return this.value;
}

public Object getTypedValue() {
if (isNil()) {
return null;
}
switch (type) {
case BOOLEAN:
return toBoolean();
case INT8:
return toInt8();
case INT16:
return toInt16();
case INT32:
return toInt32();
case INT64:
return toInt64();
case BIG_INT:
return toBigInteger();
case TIMESTAMP:
return toDatetime();
case TEXT:
case JSON:
case XML:
return toText();

case BYTES:
case VIDEO:
case IMG:
case LOCATION:
case ENCRYPTED_DATA:
return toBytesArray();

case HASH_DIGEST:
return toHashDegist();
case PUB_KEY:
return toPubKey();
case SIGNATURE_DIGEST:
return toSignatureDigest();

case DATA_CONTRACT:
return toBytesArray();
default:
throw new IllegalStateException(String.format("Type [%s] has not be supported!", type));
}
}

/**
* 是否为空值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false;
* <p>
*
* @return
*/
public boolean isNil() {
return value == null || DataType.NIL == type;
}

/**
* 返回 8 位整数值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public byte tinyValue() {
if (isNil()) {
return DataType.INT8_DEFAULT_VALUE;
}
if (DataType.INT8 == getType()) {
return toInt8();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", type));
}

private byte toInt8() {
return value.toBytes()[0];
}

/**
* 返回 16 位整数值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public short shortValue() {
if (isNil()) {
return DataType.INT16_DEFAULT_VALUE;
}
if (DataType.INT16 == getType()) {
return toInt16();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", type));
}

private short toInt16() {
return BytesUtils.toShort(value.toBytes(), 0);
}

/**
* 返回 32 位整数值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public int intValue() {
if (isNil()) {
return DataType.INT32_DEFAULT_VALUE;
}
if (DataType.INT32 == getType()) {
return toInt32();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", type));
}

private int toInt32() {
return BytesUtils.toInt(value.toBytes(), 0);
}

/**
* 返回 64 位整数值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public long longValue() {
if (isNil()) {
return DataType.INT64_DEFAULT_VALUE;
}
if (DataType.INT64 == type) {
return toInt64();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", type));

}

private long toInt64() {
return BytesUtils.toLong(value.toBytes(), 0);
}

/**
* 返回大整数值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public BigInteger bigIntValue() {
if (isNil()) {
return null;
}
if (DataType.BIG_INT == type) {
return toBigInteger();
}
throw new IllegalStateException(
String.format("Type [%s] cannot be convert to BigInteger!", type));
}

private BigInteger toBigInteger() {
return new BigInteger(value.toBytes());
}

/**
* 返回布尔值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public boolean boolValue() {
if (isNil()) {
return DataType.BOOLEAN_DEFAULT_VALUE;
}
if (DataType.BOOLEAN == type) {
return toBoolean();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", type));
}

private boolean toBoolean() {
return BytesUtils.toBoolean(value.toBytes()[0]);
}

/**
* 返回日期时间值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public Date datetimeValue() {
if (isNil()) {
return null;
}
if (DataType.TIMESTAMP == type) {
return toDatetime();
}
throw new IllegalStateException(
String.format("Type [%s] cannot be convert to datetime!", type));
}

private Date toDatetime() {
long ts = BytesUtils.toLong(value.toBytes());
return new Date(ts);
}

/**
* 返回文本值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public String stringValue() {
if (isNil()) {
return null;
}
if (type.isText()) {
return toText();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type));
}

private String toText() {
return value.toUTF8String();
}

/**
* 返回字节数组的值;
* <p>
*
* 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效;
* <p>
*
* 无效类型将引发 {@link IllegalStateException} 异常;
*
* @return
*/
public byte[] bytesValue() {
if (isNil()) {
return null;
}
if (type.isBytes()) {
return toBytesArray();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type));
}

private byte[] toBytesArray() {
return value.toBytes();
}

public HashDigest hashDigestValue() {
if (isNil()) {
return null;
}
if (DataType.HASH_DIGEST == type) {
return toHashDegist();
}
throw new IllegalStateException(
String.format("Type [%s] cannot be convert to hash digest!", type));
}

private HashDigest toHashDegist() {
return new HashDigest(toBytesArray());
}

public PubKey pubKeyValue() {
if (isNil()) {
return null;
}
if (DataType.PUB_KEY == type) {
return toPubKey();
}
throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", type));
}

private PubKey toPubKey() {
return new PubKey(toBytesArray());
}

public SignatureDigest signatureDigestValue() {
if (isNil()) {
return null;
}
if (DataType.SIGNATURE_DIGEST == type) {
return toSignatureDigest();
}
throw new IllegalStateException(
String.format("Type [%s] cannot be convert to signature digest!", type));
}

private SignatureDigest toSignatureDigest() {
return new SignatureDigest(toBytesArray());
}
public static TypedBytesValue wrap(BytesValue value) {
return new TypedBytesValue(value);
}

public static TypedBytesValue fromType(DataType type, byte[] value) {
return new TypedBytesValue(type, value);
}

public static TypedBytesValue fromBytes(byte[] value) {
return new TypedBytesValue(DataType.BYTES, value);
}

public static TypedBytesValue fromBytes(Bytes value) {
return new TypedBytesValue(DataType.BYTES, value);
}

public static TypedBytesValue fromImage(byte[] value) {
return new TypedBytesValue(DataType.IMG, value);
}

public static TypedBytesValue fromImage(Bytes value) {
return new TypedBytesValue(DataType.IMG, value);
}

/**
* 以 UTF-8 编码从字符串转换为字节数组值;
*
* @param value
* @return
*/
public static TypedBytesValue fromText(String value) {
return new TypedBytesValue(DataType.TEXT, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromJSON(String value) {
return new TypedBytesValue(DataType.JSON, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromXML(String value) {
return new TypedBytesValue(DataType.XML, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromInt32(int value) {
return new TypedBytesValue(DataType.INT32, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromInt64(long value) {
return new TypedBytesValue(DataType.INT64, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromInt16(short value) {
return new TypedBytesValue(DataType.INT16, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromInt8(byte value) {
return new TypedBytesValue(DataType.INT8, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromTimestamp(long value) {
return new TypedBytesValue(DataType.TIMESTAMP, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromBoolean(boolean value) {
return new TypedBytesValue(DataType.BOOLEAN, BytesUtils.toBytes(value));
}

public static TypedBytesValue fromPubKey(PubKey pubKey) {
return new TypedBytesValue(DataType.PUB_KEY, pubKey.toBytes());
}
}

+ 472
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue_.java View File

@@ -0,0 +1,472 @@
//package com.jd.blockchain.ledger;
//
//import java.math.BigInteger;
//import java.util.Date;
//
//import com.jd.blockchain.binaryproto.PrimitiveType;
//import com.jd.blockchain.crypto.HashDigest;
//import com.jd.blockchain.crypto.PubKey;
//import com.jd.blockchain.crypto.SignatureDigest;
//import com.jd.blockchain.utils.Bytes;
//import com.jd.blockchain.utils.io.BytesUtils;
//
//public class TypedValue_ {
//
// private BytesValue bytesValue;
//
// public TypedValue_(BytesValue bytesValue) {
// this.bytesValue = bytesValue;
// }
//
// public DataType getType() {
// return bytesValue == null ? DataType.NIL : bytesValue.getType();
// }
//
// public Object getValue() {
// if (isNil()) {
// return null;
// }
// switch (bytesValue.getType()) {
// case BOOLEAN:
// return toBoolean();
// case INT8:
// return toInt8();
// case INT16:
// return toInt16();
// case INT32:
// return toInt32();
// case INT64:
// return toInt64();
// case BIG_INT:
// return toBigInteger();
// case TIMESTAMP:
// return toDatetime();
// case TEXT:
// case JSON:
// case XML:
// return toText();
//
// case BYTES:
// case VIDEO:
// case IMG:
// case LOCATION:
// case ENCRYPTED_DATA:
// return toBytesArray();
//
// case HASH_DIGEST:
// return toHashDegist();
// case PUB_KEY:
// return toPubKey();
// case SIGNATURE_DIGEST:
// return toSignatureDigest();
//
// case DATA_CONTRACT:
// return toBytesArray();
// default:
// throw new IllegalStateException(String.format("Type [%s] has not be supported!", bytesValue.getType()));
// }
// }
//
// /**
// * 是否为空值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false;
// * <p>
// *
// * @return
// */
// public boolean isNil() {
// return bytesValue == null || DataType.NIL == bytesValue.getType();
// }
//
// /**
// * 返回 8 位整数值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public byte tinyValue() {
// if (isNil()) {
// return DataType.INT8_DEFAULT_VALUE;
// }
// if (DataType.INT8 == getType()) {
// return toInt8();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", bytesValue.getType()));
// }
//
// private byte toInt8() {
// return bytesValue.getValue().toBytes()[0];
// }
//
// /**
// * 返回 16 位整数值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public short shortValue() {
// if (isNil()) {
// return DataType.INT16_DEFAULT_VALUE;
// }
// if (DataType.INT16 == getType()) {
// return toInt16();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", bytesValue.getType()));
// }
//
// private short toInt16() {
// return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0);
// }
//
// /**
// * 返回 32 位整数值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public int intValue() {
// if (isNil()) {
// return DataType.INT32_DEFAULT_VALUE;
// }
// if (DataType.INT32 == getType()) {
// return toInt32();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", bytesValue.getType()));
// }
//
// private int toInt32() {
// return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0);
// }
//
// /**
// * 返回 64 位整数值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public long longValue() {
// if (isNil()) {
// return DataType.INT64_DEFAULT_VALUE;
// }
// if (DataType.INT64 == bytesValue.getType()) {
// return toInt64();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", bytesValue.getType()));
//
// }
//
// private long toInt64() {
// return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0);
// }
//
// /**
// * 返回大整数值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public BigInteger bigIntValue() {
// if (isNil()) {
// return null;
// }
// if (DataType.BIG_INT == bytesValue.getType()) {
// return toBigInteger();
// }
// throw new IllegalStateException(
// String.format("Type [%s] cannot be convert to BigInteger!", bytesValue.getType()));
// }
//
// private BigInteger toBigInteger() {
// return new BigInteger(bytesValue.getValue().toBytes());
// }
//
// /**
// * 返回布尔值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public boolean boolValue() {
// if (isNil()) {
// return DataType.BOOLEAN_DEFAULT_VALUE;
// }
// if (DataType.BOOLEAN == bytesValue.getType()) {
// return toBoolean();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", bytesValue.getType()));
// }
//
// private boolean toBoolean() {
// return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]);
// }
//
// /**
// * 返回日期时间值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public Date datetimeValue() {
// if (isNil()) {
// return null;
// }
// if (DataType.TIMESTAMP == bytesValue.getType()) {
// return toDatetime();
// }
// throw new IllegalStateException(
// String.format("Type [%s] cannot be convert to datetime!", bytesValue.getType()));
// }
//
// private Date toDatetime() {
// long ts = BytesUtils.toLong(bytesValue.getValue().toBytes());
// return new Date(ts);
// }
//
// /**
// * 返回文本值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public String stringValue() {
// if (isNil()) {
// return null;
// }
// DataType type = bytesValue.getType();
// if (type.isText()) {
// return toText();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type));
// }
//
// private String toText() {
// return bytesValue.getValue().toUTF8String();
// }
//
// /**
// * 返回字节数组的值;
// * <p>
// *
// * 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效;
// * <p>
// *
// * 无效类型将引发 {@link IllegalStateException} 异常;
// *
// * @return
// */
// public byte[] bytesValue() {
// if (isNil()) {
// return null;
// }
// DataType type = bytesValue.getType();
// if (type.isBytes()) {
// return toBytesArray();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type));
// }
//
// private byte[] toBytesArray() {
// return bytesValue.getValue().toBytes();
// }
//
// public HashDigest hashDigestValue() {
// if (isNil()) {
// return null;
// }
// if (DataType.HASH_DIGEST == bytesValue.getType()) {
// return toHashDegist();
// }
// throw new IllegalStateException(
// String.format("Type [%s] cannot be convert to hash digest!", bytesValue.getType()));
// }
//
// private HashDigest toHashDegist() {
// return new HashDigest(toBytesArray());
// }
//
// public PubKey pubKeyValue() {
// if (isNil()) {
// return null;
// }
// if (DataType.PUB_KEY == bytesValue.getType()) {
// return toPubKey();
// }
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", bytesValue.getType()));
// }
//
// private PubKey toPubKey() {
// return new PubKey(toBytesArray());
// }
//
// public SignatureDigest signatureDigestValue() {
// if (isNil()) {
// return null;
// }
// if (DataType.SIGNATURE_DIGEST == bytesValue.getType()) {
// return toSignatureDigest();
// }
// throw new IllegalStateException(
// String.format("Type [%s] cannot be convert to signature digest!", bytesValue.getType()));
// }
//
// private SignatureDigest toSignatureDigest() {
// return new SignatureDigest(toBytesArray());
// }
//
// public BytesValue convertToBytesValue() {
// return bytesValue == null ? TypedBytesValue.NIL : bytesValue;
// }
//
// public static TypedBytesValue fromText(String key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromText(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromBoolean(String key, boolean value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt8(String key, byte value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt8(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt16(String key, short value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt16(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt32(String key, int value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt32(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt64(String key, long value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt64(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromBytes(String key, byte[] value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromBytes(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromTimestamp(String key, long value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromJSON(String key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromJSON(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromXML(String key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromXML(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromImage(String key, byte[] value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromImage(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromText(Bytes key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromText(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromBoolean(Bytes key, boolean value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt8(Bytes key, byte value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt8(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt16(Bytes key, short value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt16(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt32(Bytes key, int value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt32(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromInt64(Bytes key, long value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromInt64(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromBytes(Bytes key, byte[] value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromBytes(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromTimestamp(Bytes key, long value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromJSON(Bytes key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromJSON(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromXML(Bytes key, String value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromXML(value);
// return new TypedBytesValue(bytesValue);
// }
//
// public static TypedBytesValue fromImage(Bytes key, byte[] value, long version) {
// BytesValue bytesValue = TypedBytesValue.fromImage(value);
// return new TypedBytesValue(bytesValue);
// }
//
//}

+ 12
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserAccountHeader.java View File

@@ -0,0 +1,12 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.consts.DataCodes;
import com.jd.blockchain.crypto.PubKey;

@DataContract(code= DataCodes.USER_ACCOUNT_HEADER)
public interface UserAccountHeader extends AccountHeader {
PubKey getDataPubKey();
}

+ 3
- 6
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserInfo.java View File

@@ -2,11 +2,8 @@ package com.jd.blockchain.ledger;

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.consts.DataCodes;
import com.jd.blockchain.crypto.PubKey;

@DataContract(code= DataCodes.USER_ACCOUNT_HEADER)
public interface UserInfo extends AccountHeader {
PubKey getDataPubKey();
@DataContract(code = DataCodes.USER_INFO)
public interface UserInfo extends UserAccountHeader {

}

+ 2
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BooleanToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -21,7 +21,7 @@ public class BooleanToBytesValueResolver extends AbstractBytesValueResolver {
if (!isSupport(type)) {
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName()));
}
return BytesData.fromBoolean((boolean) value);
return TypedBytesValue.fromBoolean((boolean) value);
}

@Override


+ 3
- 3
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -21,9 +21,9 @@ public class BytesToBytesValueResolver extends AbstractBytesValueResolver {
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName()));
}
if (type.equals(byte[].class)) {
return BytesData.fromBytes((byte[]) value);
return TypedBytesValue.fromBytes((byte[]) value);
}
return BytesData.fromBytes((Bytes) value);
return TypedBytesValue.fromBytes((Bytes) value);
}

@Override


+ 2
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -21,7 +21,7 @@ public class IntegerToBytesValueResolver extends AbstractBytesValueResolver {
if (!isSupport(type)) {
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName()));
}
return BytesData.fromInt32((int) value);
return TypedBytesValue.fromInt32((int) value);
}

@Override


+ 2
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -21,7 +21,7 @@ public class LongToBytesValueResolver extends AbstractBytesValueResolver {
if (!isSupport(type)) {
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName()));
}
return BytesData.fromInt64((long)value);
return TypedBytesValue.fromInt64((long)value);
}

@Override


+ 2
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -21,7 +21,7 @@ public class ShortToBytesValueResolver extends AbstractBytesValueResolver {
if (!isSupport(type)) {
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName()));
}
return BytesData.fromInt16((short)value);
return TypedBytesValue.fromInt16((short)value);
}

@Override


+ 3
- 3
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java View File

@@ -1,6 +1,6 @@
package com.jd.blockchain.ledger.resolver;

import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataType;
import com.jd.blockchain.utils.Bytes;
@@ -26,10 +26,10 @@ public class StringToBytesValueResolver extends AbstractBytesValueResolver {
// 类型判断
String valString = (String)value;
if (JSONSerializeUtils.isJSON(valString)) {
return BytesData.fromJSON(valString);
return TypedBytesValue.fromJSON(valString);
}
// 暂不处理XML格式
return BytesData.fromText(valString);
return TypedBytesValue.fromText(valString);
}

@Override


+ 9
- 9
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java View File

@@ -1,7 +1,7 @@
package com.jd.blockchain.transaction;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.utils.Bytes;
@@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe
@Override
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) {
BytesValue bytesValue = BytesData.fromBytes(value);
BytesValue bytesValue = TypedBytesValue.fromBytes(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) {
BytesValue bytesValue = BytesData.fromImage(value);
BytesValue bytesValue = TypedBytesValue.fromImage(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe
@Override
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromText(value);
BytesValue bytesValue = TypedBytesValue.fromText(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) {
BytesValue bytesValue = BytesData.fromBytes(value);
BytesValue bytesValue = TypedBytesValue.fromBytes(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) {
BytesValue bytesValue = BytesData.fromInt64(value);
BytesValue bytesValue = TypedBytesValue.fromInt64(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromJSON(value);
BytesValue bytesValue = TypedBytesValue.fromJSON(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) {
BytesValue bytesValue = BytesData.fromXML(value);
BytesValue bytesValue = TypedBytesValue.fromXML(value);
operation.set(key, bytesValue, expVersion);
return this;
}
@Override
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) {
BytesValue bytesValue = BytesData.fromTimestamp(value);
BytesValue bytesValue = TypedBytesValue.fromTimestamp(value);
operation.set(key, bytesValue, expVersion);
return this;
}


+ 2
- 2
source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/ContractEventSendOpTemplateTest.java View File

@@ -16,7 +16,7 @@ import org.junit.Test;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.BytesDataList;
import com.jd.blockchain.ledger.BytesValueList;
import com.jd.blockchain.ledger.ContractEventSendOperation;
@@ -41,7 +41,7 @@ public class ContractEventSendOpTemplateTest {
DataContractRegistry.register(ContractEventSendOperation.class);
DataContractRegistry.register(Operation.class);
String contractAddress = "zhangsan-address", event = "zhangsan-event";
BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args"));
BytesValueList args = new BytesDataList(TypedBytesValue.fromText("zhangsan-args"));
data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args);
}



+ 4
- 4
source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/DataAccountKVSetOpTemplateTest.java View File

@@ -16,7 +16,7 @@ import org.junit.Test;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate;
@@ -41,11 +41,11 @@ public class DataAccountKVSetOpTemplateTest {
String accountAddress = "zhangsandhakhdkah";
data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress));
KVData kvData1 =
new KVData("test1", BytesData.fromText("zhangsan"), 9999L);
new KVData("test1", TypedBytesValue.fromText("zhangsan"), 9999L);
KVData kvData2 =
new KVData("test2", BytesData.fromText("lisi"), 9990L);
new KVData("test2", TypedBytesValue.fromText("lisi"), 9990L);
KVData kvData3 =
new KVData("test3", BytesData.fromText("wangwu"), 1990L);
new KVData("test3", TypedBytesValue.fromText("wangwu"), 1990L);
data.set(kvData1);
data.set(kvData2);
data.set(kvData3);


+ 2
- 2
source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/KVDataTest.java View File

@@ -16,7 +16,7 @@ import org.junit.Test;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.TypedBytesValue;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate;
import com.jd.blockchain.transaction.KVData;
@@ -38,7 +38,7 @@ public class KVDataTest {
byte[] value = "test-value".getBytes();
long expectedVersion = 9999L;

kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion);
kvData = new KVData(key, TypedBytesValue.fromBytes(value), expectedVersion);
}

@Test


+ 4
- 3
source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java View File

@@ -151,7 +151,7 @@ public class ClientResolveUtil {
String realValBase58 = valueObj.getJSONObject("value").getString("value");
String key = currWriteSetObj.getString("key");
DataType dataType = DataType.valueOf(typeStr);
BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58));
BytesValue bytesValue = TypedBytesValue.fromType(dataType, Base58Utils.decode(realValBase58));
KVData kvData = new KVData(key, bytesValue, expectedVersion);
kvOperation.set(kvData);
}
@@ -200,7 +200,7 @@ public class ClientResolveUtil {
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey");
String pubKeyBase58 = pubKeyObj.getString("value");
// 生成ParticipantNode对象
ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()));
ParticipantCertData participantCertData = new ParticipantCertData(id, address, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()), null);
participantNodes[i] = participantCertData;
}
ledgerInitSettingData.setConsensusParticipants(participantNodes);
@@ -294,11 +294,12 @@ public class ClientResolveUtil {
this.pubKey = participantNode.getPubKey();
}

public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey) {
public ParticipantCertData(int id, Bytes address, String name, PubKey pubKey, ParticipantNodeState participantNodeState) {
this.id = id;
this.address = address;
this.name = name;
this.pubKey = pubKey;
this.participantNodeState = participantNodeState;
}



+ 1
- 1
source/storage/storage-redis/src/main/java/com/jd/blockchain/storage/service/impl/redis/RedisVerioningStorage.java View File

@@ -1,8 +1,8 @@
package com.jd.blockchain.storage.service.impl.redis;

import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


+ 1
- 1
source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBVersioningStorage.java View File

@@ -7,9 +7,9 @@ import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.collections4.map.LRUMap;
import org.rocksdb.*;

import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.io.BytesUtils;

/**


+ 0
- 20
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVEntry.java View File

@@ -1,20 +0,0 @@
package com.jd.blockchain.storage.service;
import com.jd.blockchain.utils.Bytes;
/**
* 版本化的键值数据项;
*
* @author huanghaiquan
*
*/
public interface VersioningKVEntry {
// String getKey();
Bytes getKey();
long getVersion();
byte[] getValue();
}

+ 2
- 1
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/VersioningKVStorage.java View File

@@ -1,6 +1,7 @@
package com.jd.blockchain.storage.service;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;
/**
* Versioning Key-Value Storage
@@ -40,7 +41,7 @@ public interface VersioningKVStorage extends BatchStorageService {
* @param version
* @return
*/
VersioningKVEntry getEntry(Bytes key, long version);
VersioningKVEntry<Bytes, byte[]> getEntry(Bytes key, long version);
/**
* Return the specified verson's value; <br>


+ 5
- 5
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/BufferedKVStorage.java View File

@@ -7,10 +7,10 @@ import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.Transactional;
import com.jd.blockchain.utils.VersioningKVEntry;

/**
* {@link BufferedKVStorage} 缓冲写入的KV存储;<br>
@@ -77,9 +77,9 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage
}
return ws.getLatestVersion();
}
@Override
public VersioningKVEntry getEntry(Bytes key, long version) {
public VersioningKVEntry<Bytes, byte[]> getEntry(Bytes key, long version) {
VersioningWritingSet ws = versioningCache.get(key);
if (ws == null) {
return origVersioningStorage.getEntry(key, version);
@@ -484,7 +484,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage
return startingVersion;
}

public VersioningKVEntry getEntry(long version) {
public VersioningKVEntry<Bytes, byte[]> getEntry(long version) {
byte[] value = get(version);
if (value == null) {
return null;
@@ -505,7 +505,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage
}
}

private static class VersioningKVData implements VersioningKVEntry {
private static class VersioningKVData implements VersioningKVEntry<Bytes, byte[]> {

private Bytes key;



+ 1
- 1
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java View File

@@ -5,9 +5,9 @@ import java.util.Set;

import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.KVStorageService;
import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.io.BytesMap;

public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap<Bytes> {


+ 7
- 8
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVData.java View File

@@ -1,24 +1,23 @@
package com.jd.blockchain.storage.service.utils;

import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;

public class VersioningKVData implements VersioningKVEntry {
public class VersioningKVData<K, V> implements VersioningKVEntry<K, V> {

private Bytes key;
private K key;

private long version;

private byte[] value;
private V value;

public VersioningKVData(Bytes key, long version, byte[] value) {
public VersioningKVData(K key, long version, V value) {
this.key = key;
this.version = version;
this.value = value;
}

@Override
public Bytes getKey() {
public K getKey() {
return key;
}

@@ -28,7 +27,7 @@ public class VersioningKVData implements VersioningKVEntry {
}

@Override
public byte[] getValue() {
public V getValue() {
return value;
}


+ 1
- 1
source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/VersioningKVStorageMap.java View File

@@ -5,9 +5,9 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.jd.blockchain.storage.service.VersioningKVEntry;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.VersioningKVEntry;
import com.jd.blockchain.utils.io.BytesMap;

public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap<Bytes> {


+ 122
- 0
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/RegionMap.java View File

@@ -0,0 +1,122 @@
package com.jd.blockchain.utils;

public abstract class RegionMap<K, V> implements VersioningMap<K, V> {

private K region;

private VersioningMap<K, V> dataMap;

public RegionMap(K region, VersioningMap<K, V> dataMap) {
this.region = region;
this.dataMap = dataMap;
}

@Override
public long setValue(K key, V value, long version) {
K dataKey = concatKey(region, key);
return dataMap.setValue(dataKey, value, version);
}

@Override
public V getValue(K key, long version) {
K dataKey = concatKey(region, key);
return dataMap.getValue(dataKey, version);
}

@Override
public V getValue(K key) {
K dataKey = concatKey(region, key);
return dataMap.getValue(dataKey);
}

@Override
public long getVersion(K key) {
K dataKey = concatKey(region, key);
return dataMap.getVersion(dataKey);
}

@Override
public VersioningKVEntry<K, V> getDataEntry(K key) {
K dataKey = concatKey(region, key);
VersioningKVEntry<K, V> entry = dataMap.getDataEntry(dataKey);
return new KVEntryWrapper<K, V>(key, entry);
}

@Override
public VersioningKVEntry<K, V> getDataEntry(K key, long version) {
K dataKey = concatKey(region, key);
VersioningKVEntry<K, V> entry = dataMap.getDataEntry(dataKey, version);
return new KVEntryWrapper<K, V>(key, entry);
}

/**
* 以指定的前缀组成新的key;
*
* @param prefix
* @param key
* @return
*/
protected abstract K concatKey(K prefix, K key);

public static <V> VersioningMap<Bytes, V> newRegion(Bytes region, VersioningMap<Bytes, V> dataMap) {
return new BytesKeyRegionMap<V>(region, dataMap);
}
public static <V> VersioningMap<String, V> newRegion(String region, VersioningMap<String, V> dataMap) {
return new StringKeyRegionMap<V>(region, dataMap);
}

private static class BytesKeyRegionMap<V> extends RegionMap<Bytes, V> {

public BytesKeyRegionMap(Bytes region, VersioningMap<Bytes, V> dataMap) {
super(region, dataMap);
}

@Override
protected Bytes concatKey(Bytes prefix, Bytes key) {
return prefix.concat(key);
}

}

private static class StringKeyRegionMap<V> extends RegionMap<String, V> {

public StringKeyRegionMap(String region, VersioningMap<String, V> dataMap) {
super(region, dataMap);
}

@Override
protected String concatKey(String prefix, String key) {
return prefix + key;
}

}

private static class KVEntryWrapper<K, V> implements VersioningKVEntry<K, V> {

private K key;

private VersioningKVEntry<K, V> entry;

public KVEntryWrapper(K key, VersioningKVEntry<K, V> entry) {
this.key = key;
this.entry = entry;
}

@Override
public K getKey() {
return key;
}

@Override
public long getVersion() {
return entry.getVersion();
}

@Override
public V getValue() {
return entry.getValue();
}

}
}

+ 17
- 0
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/VersioningKVEntry.java View File

@@ -0,0 +1,17 @@
package com.jd.blockchain.utils;
/**
* 版本化的键值数据项;
*
* @author huanghaiquan
*
*/
public interface VersioningKVEntry<K, V>{
K getKey();
long getVersion();
V getValue();
}

+ 116
- 0
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/VersioningMap.java View File

@@ -0,0 +1,116 @@
package com.jd.blockchain.utils;

public interface VersioningMap<K, V> {
// long getDataCount();

// /**
// * Create or update the value associated the specified key if the version
// * checking is passed.<br>
// *
// * The value of the key will be updated only if it's latest version equals the
// * specified version argument. <br>
// * If the key doesn't exist, it will be created when the version arg was -1.
// * <p>
// * If updating is performed, the version of the key increase by 1. <br>
// * If creating is performed, the version of the key initialize by 0. <br>
// *
// * @param key The key of data;
// * @param value The value of data;
// * @param version The expected latest version of the key.
// * @return The new version of the key. <br>
// * If the key is new created success, then return 0; <br>
// * If the key is updated success, then return the new version;<br>
// * If this operation fail by version checking or other reason, then
// * return -1;
// */
// long setValue(String key, byte[] value, long version);

/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, it will be created when the version arg was -1.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected latest version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
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>
*
* 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
*/
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;
*
* @param key
* @return return null if not exist;
*/
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;
*
* @param key
* @return
*/
long getVersion(K key);

/**
*
* @param key
* @return Null if the key doesn't exist!
*/
VersioningKVEntry<K, V> getDataEntry(K key);

VersioningKVEntry<K, V> getDataEntry(K key, long version);

}

Loading…
Cancel
Save