@@ -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; | |||
@@ -21,8 +21,6 @@ class DynamicDataContract implements InvocationHandler { | |||
private DataContractEncoderImpl contractEncoder; | |||
// private BytesSlice contractBytes; | |||
// 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段; | |||
private BytesSlices[] dataSlices; | |||
@@ -1,12 +1,11 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface AccountQuery<T> extends MerkleProvable { | |||
AccountHeader[] getHeaders(int fromIndex, int count); | |||
/** | |||
* 返回总数; | |||
* | |||
@@ -14,7 +13,15 @@ public interface AccountQuery<T> extends MerkleProvable { | |||
*/ | |||
long getTotal(); | |||
BlockchainIdentity[] getHeaders(int fromIndex, int count); | |||
boolean contains(Bytes address); | |||
/** | |||
* get proof of specified account; | |||
*/ | |||
@Override | |||
MerkleProof getProof(Bytes address); | |||
/** | |||
* 返回账户实例; | |||
@@ -0,0 +1,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> { | |||
} |
@@ -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) { | |||
@@ -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 { | |||
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
//package com.jd.blockchain.ledger.core; | |||
// | |||
//import com.jd.blockchain.crypto.HashDigest; | |||
//import com.jd.blockchain.ledger.AccountHeader; | |||
//import com.jd.blockchain.ledger.CryptoSetting; | |||
//import com.jd.blockchain.ledger.MerkleProof; | |||
//import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
//import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
//import com.jd.blockchain.utils.Bytes; | |||
//import com.jd.blockchain.utils.Transactional; | |||
// | |||
//public class GenericAccountSet<H extends AccountHeader, T extends GenericAccount<H>> implements AccountQuery<H, T>, Transactional { | |||
// | |||
// private Class<H> headerType; | |||
// | |||
// private MerkleAccountSet merkleAccountSet; | |||
// | |||
// public GenericAccountSet(Class<H> headerType, CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | |||
// VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
// this(headerType, null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); | |||
// } | |||
// | |||
// public GenericAccountSet(Class<H> headerType, HashDigest rootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
// ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
// AccountAccessPolicy accessPolicy) { | |||
// this.headerType = headerType; | |||
// this.merkleAccountSet = new MerkleAccountSet(rootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly, accessPolicy); | |||
// } | |||
// | |||
// @Override | |||
// public MerkleProof getProof(Bytes address) { | |||
// return merkleAccountSet.getProof(address); | |||
// } | |||
// | |||
// @Override | |||
// public HashDigest getRootHash() { | |||
// return merkleAccountSet.getRootHash(); | |||
// } | |||
// | |||
// @Override | |||
// public boolean isUpdated() { | |||
// return merkleAccountSet.isUpdated(); | |||
// } | |||
// | |||
// @Override | |||
// public void commit() { | |||
// merkleAccountSet.commit(); | |||
// } | |||
// | |||
// @Override | |||
// public void cancel() { | |||
// merkleAccountSet.cancel(); | |||
// } | |||
// | |||
// @Override | |||
// public H[] getHeaders(int fromIndex, int count) { | |||
// merkleAccountSet.getHeaders(fromIndex, count) | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public long getTotal() { | |||
// // TODO Auto-generated method stub | |||
// return 0; | |||
// } | |||
// | |||
// @Override | |||
// public boolean contains(Bytes address) { | |||
// // TODO Auto-generated method stub | |||
// return false; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(String address) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(Bytes address) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public T getAccount(Bytes address, long version) { | |||
// // TODO Auto-generated method stub | |||
// return null; | |||
// } | |||
// | |||
// | |||
//} |
@@ -0,0 +1,42 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.HashProof; | |||
/** | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class HashDegistList implements HashProof { | |||
private List<HashDigest> proofs = new ArrayList<HashDigest>(); | |||
public HashDegistList() { | |||
} | |||
public HashDegistList(HashProof proof) { | |||
concat(proof); | |||
} | |||
public void concat(HashProof proof) { | |||
int levels = proof.getLevels(); | |||
for (int i = levels; i > -1; i--) { | |||
proofs.add(proof.getHash(i)); | |||
} | |||
} | |||
@Override | |||
public int getLevels() { | |||
return proofs.size(); | |||
} | |||
@Override | |||
public HashDigest getHash(int level) { | |||
return proofs.get(level); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.HashProof; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface HashProvable { | |||
HashProof getProof(Bytes key); | |||
} |
@@ -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(); | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
// | |||
//} |
@@ -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); | |||
// } | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} | |||
@@ -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 { | |||
@@ -0,0 +1,7 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.utils.VersioningMap; | |||
public interface StringKeyMap<V> extends VersioningMap<String, V> { | |||
} |
@@ -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(); | |||
} | |||
@@ -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); | |||
} | |||
@@ -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; | |||
@@ -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; | |||
@@ -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); | |||
@@ -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()); | |||
@@ -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 { | |||
@@ -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()) | |||
@@ -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(); | |||
@@ -1,118 +0,0 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
/** | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BytesData implements BytesValue { | |||
DataType type; | |||
Bytes value; | |||
private BytesData(DataType type, byte[] bytes) { | |||
this.type = type; | |||
this.value = new Bytes(bytes); | |||
} | |||
private BytesData(DataType type, Bytes bytes) { | |||
this.type = type; | |||
this.value = bytes; | |||
} | |||
public static BytesValue fromType(DataType type, byte[] value) { | |||
return new BytesData(type, value); | |||
} | |||
public static BytesValue fromBytes(byte[] value) { | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromBytes(Bytes value) { | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromImage(byte[] value) { | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
public static BytesValue fromImage(Bytes value) { | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
/** | |||
* 以 UTF-8 编码从字符串转换为字节数组值; | |||
* | |||
* @param value | |||
* @return | |||
*/ | |||
public static BytesValue fromText(String value) { | |||
return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); | |||
} | |||
/** | |||
* 以 UTF-8 编码把字节数组值转换为字符串; | |||
* | |||
* @param bytesValue | |||
* @return | |||
*/ | |||
public static String toText(BytesValue bytesValue) { | |||
if (bytesValue == null) { | |||
return null; | |||
} | |||
if (bytesValue.getType() != DataType.TEXT) { | |||
throw new ValueTypeCastException("The expected value type is " + DataType.TEXT.toString() | |||
+ ", but it is actually " + bytesValue.getType().toString() + "!"); | |||
} | |||
return bytesValue.getValue().toUTF8String(); | |||
} | |||
public static BytesValue fromJSON(String value) { | |||
return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromXML(String value) { | |||
return new BytesData(DataType.XML, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt32(int value) { | |||
return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt64(long value) { | |||
return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt16(short value) { | |||
return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt8(byte value) { | |||
return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromTimestamp(long value) { | |||
return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromBoolean(boolean value) { | |||
return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
} | |||
@Override | |||
public DataType getType() { | |||
return this.type; | |||
} | |||
public void setType(DataType type) { | |||
this.type = type; | |||
} | |||
@Override | |||
public Bytes getValue() { | |||
return this.value; | |||
} | |||
} |
@@ -14,18 +14,18 @@ public class BytesDataList implements BytesValueList { | |||
} | |||
public static BytesValueList singleText(String value) { | |||
return new BytesDataList(BytesData.fromText(value)); | |||
return new BytesDataList(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)); | |||
} | |||
} |
@@ -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) { | |||
@@ -106,6 +106,20 @@ public enum DataType { | |||
* DataContract 数据; | |||
*/ | |||
DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); | |||
public static final boolean BOOLEAN_DEFAULT_VALUE = false; | |||
public static final byte INT8_DEFAULT_VALUE = 0; | |||
public static final short INT16_DEFAULT_VALUE = 0; | |||
public static final int INT32_DEFAULT_VALUE = 0; | |||
public static final long INT64_DEFAULT_VALUE = 0; | |||
@EnumField(type = PrimitiveType.INT8) | |||
public final byte CODE; | |||
@@ -114,6 +128,51 @@ public enum DataType { | |||
this.CODE = code; | |||
} | |||
/** | |||
* 是否表示“文本类型”或“文本衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isText() { | |||
return BaseType.TEXT == (BaseType.TEXT & CODE); | |||
} | |||
/** | |||
* 是否表示“字节类型”或“字节衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBytes() { | |||
return BaseType.BYTES == (BaseType.BYTES & CODE); | |||
} | |||
/** | |||
* 是否表示“整数类型”或“整数衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isInteger() { | |||
return BaseType.INTEGER == (BaseType.INTEGER & CODE); | |||
} | |||
/** | |||
* 是否表示“布尔类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBoolean() { | |||
return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE); | |||
} | |||
/** | |||
* 是否表示“扩展类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isExt() { | |||
return BaseType.EXT == (BaseType.EXT & CODE); | |||
} | |||
public static DataType valueOf(byte code) { | |||
for (DataType dataType : DataType.values()) { | |||
if (dataType.CODE == code) { | |||
@@ -0,0 +1,44 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public interface HashProof { | |||
/** | |||
* 最大层级数; <br> | |||
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
* | |||
* @return | |||
* | |||
* @see MerkleTree#getLevel() | |||
*/ | |||
int getLevels(); | |||
/** | |||
* 返回证明中指定层级的节点的哈希; | |||
* <p> | |||
* | |||
* @param level | |||
* 参数值为 0 返回的是数据节点的哈希; <br> | |||
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
* @return | |||
*/ | |||
HashDigest getHash(int level); | |||
/** | |||
* 返回根节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getRootHash() { | |||
return getHash(getLevels()); | |||
} | |||
/** | |||
* 返回数据节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getDataHash() { | |||
return getHash(0); | |||
} | |||
} |
@@ -1,8 +1,6 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public interface MerkleProof { | |||
public interface MerkleProof extends HashProof { | |||
/** | |||
* 所证明的数据节点的序列号; | |||
@@ -11,62 +9,46 @@ public interface MerkleProof { | |||
*/ | |||
long getSN(); | |||
/** | |||
* 最大层级数; <br> | |||
* 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
* | |||
* @return | |||
* | |||
* @see MerkleTree#getLevel() | |||
*/ | |||
int getLevels(); | |||
/** | |||
* 返回证明中指定层级的节点的哈希; | |||
* <p> | |||
* | |||
* @param level | |||
* 参数值为 0 返回的是数据节点的哈希; <br> | |||
* 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
* @return | |||
*/ | |||
HashDigest getHash(int level); | |||
MerkleNode getNode(int level); | |||
// /** | |||
// * 返回证明中指定层级的数据起始序号; | |||
// * 最大层级数; <br> | |||
// * 叶子节点(即数据节点)的层级为 0,数据节点之上的每一级父节点的层级加 1, 最大层级便是根节点的层级; | |||
// * | |||
// * @param level | |||
// * @return | |||
// * | |||
// * @see MerkleTree#getLevel() | |||
// */ | |||
// long getStartingSN(int level); | |||
// int getLevels(); | |||
// | |||
// /** | |||
// * 返回证明中指定层级的数据记录总数; | |||
// * 返回证明中指定层级的节点的哈希; | |||
// * <p> | |||
// * | |||
// * @param level | |||
// * 参数值为 0 返回的是数据节点的哈希; <br> | |||
// * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||
// * @return | |||
// */ | |||
// long getDataCount(int level); | |||
// HashDigest getHash(int level); | |||
/** | |||
* 返回根节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getRootHash() { | |||
return getHash(getLevels()); | |||
} | |||
MerkleNode getNode(int level); | |||
/** | |||
* 返回数据节点的哈希; | |||
* | |||
* @return | |||
*/ | |||
default HashDigest getDataHash() { | |||
return getHash(0); | |||
} | |||
// * 返回根节点的哈希; | |||
// * | |||
// * @return | |||
// */ | |||
// default HashDigest getRootHash() { | |||
// return getHash(getLevels()); | |||
// } | |||
// | |||
// /** | |||
// * 返回数据节点的哈希; | |||
// * | |||
// * @return | |||
// */ | |||
// default HashDigest getDataHash() { | |||
// return getHash(0); | |||
// } | |||
default MerkleDataNode getDataNode() { | |||
return (MerkleDataNode)getNode(0); | |||
@@ -0,0 +1,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()); | |||
} | |||
} |
@@ -0,0 +1,472 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import java.math.BigInteger; | |||
//import java.util.Date; | |||
// | |||
//import com.jd.blockchain.binaryproto.PrimitiveType; | |||
//import com.jd.blockchain.crypto.HashDigest; | |||
//import com.jd.blockchain.crypto.PubKey; | |||
//import com.jd.blockchain.crypto.SignatureDigest; | |||
//import com.jd.blockchain.utils.Bytes; | |||
//import com.jd.blockchain.utils.io.BytesUtils; | |||
// | |||
//public class TypedValue_ { | |||
// | |||
// private BytesValue bytesValue; | |||
// | |||
// public TypedValue_(BytesValue bytesValue) { | |||
// this.bytesValue = bytesValue; | |||
// } | |||
// | |||
// public DataType getType() { | |||
// return bytesValue == null ? DataType.NIL : bytesValue.getType(); | |||
// } | |||
// | |||
// public Object getValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// switch (bytesValue.getType()) { | |||
// case BOOLEAN: | |||
// return toBoolean(); | |||
// case INT8: | |||
// return toInt8(); | |||
// case INT16: | |||
// return toInt16(); | |||
// case INT32: | |||
// return toInt32(); | |||
// case INT64: | |||
// return toInt64(); | |||
// case BIG_INT: | |||
// return toBigInteger(); | |||
// case TIMESTAMP: | |||
// return toDatetime(); | |||
// case TEXT: | |||
// case JSON: | |||
// case XML: | |||
// return toText(); | |||
// | |||
// case BYTES: | |||
// case VIDEO: | |||
// case IMG: | |||
// case LOCATION: | |||
// case ENCRYPTED_DATA: | |||
// return toBytesArray(); | |||
// | |||
// case HASH_DIGEST: | |||
// return toHashDegist(); | |||
// case PUB_KEY: | |||
// return toPubKey(); | |||
// case SIGNATURE_DIGEST: | |||
// return toSignatureDigest(); | |||
// | |||
// case DATA_CONTRACT: | |||
// return toBytesArray(); | |||
// default: | |||
// throw new IllegalStateException(String.format("Type [%s] has not be supported!", bytesValue.getType())); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * 是否为空值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; | |||
// * <p> | |||
// * | |||
// * @return | |||
// */ | |||
// public boolean isNil() { | |||
// return bytesValue == null || DataType.NIL == bytesValue.getType(); | |||
// } | |||
// | |||
// /** | |||
// * 返回 8 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public byte tinyValue() { | |||
// if (isNil()) { | |||
// return DataType.INT8_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT8 == getType()) { | |||
// return toInt8(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int8!", bytesValue.getType())); | |||
// } | |||
// | |||
// private byte toInt8() { | |||
// return bytesValue.getValue().toBytes()[0]; | |||
// } | |||
// | |||
// /** | |||
// * 返回 16 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public short shortValue() { | |||
// if (isNil()) { | |||
// return DataType.INT16_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT16 == getType()) { | |||
// return toInt16(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int16!", bytesValue.getType())); | |||
// } | |||
// | |||
// private short toInt16() { | |||
// return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回 32 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public int intValue() { | |||
// if (isNil()) { | |||
// return DataType.INT32_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT32 == getType()) { | |||
// return toInt32(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int32!", bytesValue.getType())); | |||
// } | |||
// | |||
// private int toInt32() { | |||
// return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回 64 位整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public long longValue() { | |||
// if (isNil()) { | |||
// return DataType.INT64_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.INT64 == bytesValue.getType()) { | |||
// return toInt64(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to Int64!", bytesValue.getType())); | |||
// | |||
// } | |||
// | |||
// private long toInt64() { | |||
// return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); | |||
// } | |||
// | |||
// /** | |||
// * 返回大整数值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public BigInteger bigIntValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.BIG_INT == bytesValue.getType()) { | |||
// return toBigInteger(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to BigInteger!", bytesValue.getType())); | |||
// } | |||
// | |||
// private BigInteger toBigInteger() { | |||
// return new BigInteger(bytesValue.getValue().toBytes()); | |||
// } | |||
// | |||
// /** | |||
// * 返回布尔值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public boolean boolValue() { | |||
// if (isNil()) { | |||
// return DataType.BOOLEAN_DEFAULT_VALUE; | |||
// } | |||
// if (DataType.BOOLEAN == bytesValue.getType()) { | |||
// return toBoolean(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to boolean!", bytesValue.getType())); | |||
// } | |||
// | |||
// private boolean toBoolean() { | |||
// return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); | |||
// } | |||
// | |||
// /** | |||
// * 返回日期时间值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public Date datetimeValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.TIMESTAMP == bytesValue.getType()) { | |||
// return toDatetime(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to datetime!", bytesValue.getType())); | |||
// } | |||
// | |||
// private Date toDatetime() { | |||
// long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); | |||
// return new Date(ts); | |||
// } | |||
// | |||
// /** | |||
// * 返回文本值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为“文本类型”或“文本衍生类型”时有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public String stringValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// DataType type = bytesValue.getType(); | |||
// if (type.isText()) { | |||
// return toText(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to text!", type)); | |||
// } | |||
// | |||
// private String toText() { | |||
// return bytesValue.getValue().toUTF8String(); | |||
// } | |||
// | |||
// /** | |||
// * 返回字节数组的值; | |||
// * <p> | |||
// * | |||
// * 仅当数据类型 {@link #getType()} 为“字节类型”或“字节衍生类型”时有效; | |||
// * <p> | |||
// * | |||
// * 无效类型将引发 {@link IllegalStateException} 异常; | |||
// * | |||
// * @return | |||
// */ | |||
// public byte[] bytesValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// DataType type = bytesValue.getType(); | |||
// if (type.isBytes()) { | |||
// return toBytesArray(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to bytes!", type)); | |||
// } | |||
// | |||
// private byte[] toBytesArray() { | |||
// return bytesValue.getValue().toBytes(); | |||
// } | |||
// | |||
// public HashDigest hashDigestValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.HASH_DIGEST == bytesValue.getType()) { | |||
// return toHashDegist(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to hash digest!", bytesValue.getType())); | |||
// } | |||
// | |||
// private HashDigest toHashDegist() { | |||
// return new HashDigest(toBytesArray()); | |||
// } | |||
// | |||
// public PubKey pubKeyValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.PUB_KEY == bytesValue.getType()) { | |||
// return toPubKey(); | |||
// } | |||
// throw new IllegalStateException(String.format("Type [%s] cannot be convert to pub key!", bytesValue.getType())); | |||
// } | |||
// | |||
// private PubKey toPubKey() { | |||
// return new PubKey(toBytesArray()); | |||
// } | |||
// | |||
// public SignatureDigest signatureDigestValue() { | |||
// if (isNil()) { | |||
// return null; | |||
// } | |||
// if (DataType.SIGNATURE_DIGEST == bytesValue.getType()) { | |||
// return toSignatureDigest(); | |||
// } | |||
// throw new IllegalStateException( | |||
// String.format("Type [%s] cannot be convert to signature digest!", bytesValue.getType())); | |||
// } | |||
// | |||
// private SignatureDigest toSignatureDigest() { | |||
// return new SignatureDigest(toBytesArray()); | |||
// } | |||
// | |||
// public BytesValue convertToBytesValue() { | |||
// return bytesValue == null ? TypedBytesValue.NIL : bytesValue; | |||
// } | |||
// | |||
// public static TypedBytesValue fromText(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromText(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBoolean(String key, boolean value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt8(String key, byte value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt8(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt16(String key, short value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt16(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt32(String key, int value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt32(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt64(String key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt64(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBytes(String key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromTimestamp(String key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromJSON(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromJSON(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromXML(String key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromXML(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromImage(String key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromImage(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromText(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromText(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBoolean(Bytes key, boolean value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBoolean(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt8(Bytes key, byte value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt8(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt16(Bytes key, short value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt16(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt32(Bytes key, int value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt32(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromInt64(Bytes key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromInt64(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromBytes(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromTimestamp(Bytes key, long value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromJSON(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromJSON(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromXML(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromXML(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
// public static TypedBytesValue fromImage(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedBytesValue.fromImage(value); | |||
// return new TypedBytesValue(bytesValue); | |||
// } | |||
// | |||
//} |
@@ -0,0 +1,12 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.PubKey; | |||
@DataContract(code= DataCodes.USER_ACCOUNT_HEADER) | |||
public interface UserAccountHeader extends AccountHeader { | |||
PubKey getDataPubKey(); | |||
} |
@@ -2,11 +2,8 @@ package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.PubKey; | |||
@DataContract(code= DataCodes.USER_ACCOUNT_HEADER) | |||
public interface UserInfo extends AccountHeader { | |||
PubKey getDataPubKey(); | |||
@DataContract(code = DataCodes.USER_INFO) | |||
public interface UserInfo extends UserAccountHeader { | |||
} |
@@ -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 | |||
@@ -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 | |||
@@ -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 | |||
@@ -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 | |||
@@ -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 | |||
@@ -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 | |||
@@ -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; | |||
} | |||
@@ -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); | |||
} | |||
@@ -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); | |||
@@ -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 | |||
@@ -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,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; | |||
@@ -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; | |||
/** | |||
@@ -1,20 +0,0 @@ | |||
package com.jd.blockchain.storage.service; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 版本化的键值数据项; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface VersioningKVEntry { | |||
// String getKey(); | |||
Bytes getKey(); | |||
long getVersion(); | |||
byte[] getValue(); | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.jd.blockchain.storage.service; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.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> | |||
@@ -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; | |||
@@ -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> { | |||
@@ -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; | |||
} | |||
@@ -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> { | |||
@@ -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(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
package com.jd.blockchain.utils; | |||
/** | |||
* 版本化的键值数据项; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface VersioningKVEntry<K, V>{ | |||
K getKey(); | |||
long getVersion(); | |||
V getValue(); | |||
} |
@@ -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); | |||
} |