@@ -122,11 +122,15 @@ public interface DataCodes { | |||||
public static final int ACCOUNT_HEADER = 0x710; | public static final int ACCOUNT_HEADER = 0x710; | ||||
public static final int USER_ACCOUNT_HEADER = 0x800; | public static final int USER_ACCOUNT_HEADER = 0x800; | ||||
public static final int USER_INFO = 0x801; | |||||
public static final int DATA = 0x900; | public static final int DATA = 0x900; | ||||
// contract related; | // contract related; | ||||
public static final int CONTRACT_ACCOUNT_HEADER = 0xA00; | public static final int CONTRACT_ACCOUNT_HEADER = 0xA00; | ||||
public static final int CONTRACT_INFO = 0xA01; | |||||
// ...0xA19 | // ...0xA19 | ||||
public static final int HASH = 0xB00; | public static final int HASH = 0xB00; | ||||
@@ -21,8 +21,6 @@ class DynamicDataContract implements InvocationHandler { | |||||
private DataContractEncoderImpl contractEncoder; | private DataContractEncoderImpl contractEncoder; | ||||
// private BytesSlice contractBytes; | |||||
// 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段; | // 字段的数据片段列表,首个是 HeaderSlice,其次是按字段顺序排列的数据片段; | ||||
private BytesSlices[] dataSlices; | private BytesSlices[] dataSlices; | ||||
@@ -1,12 +1,11 @@ | |||||
package com.jd.blockchain.ledger.core; | 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; | import com.jd.blockchain.utils.Bytes; | ||||
public interface AccountQuery<T> extends MerkleProvable { | public interface AccountQuery<T> extends MerkleProvable { | ||||
AccountHeader[] getHeaders(int fromIndex, int count); | |||||
/** | /** | ||||
* 返回总数; | * 返回总数; | ||||
* | * | ||||
@@ -14,7 +13,15 @@ public interface AccountQuery<T> extends MerkleProvable { | |||||
*/ | */ | ||||
long getTotal(); | long getTotal(); | ||||
BlockchainIdentity[] getHeaders(int fromIndex, int count); | |||||
boolean contains(Bytes address); | 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.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.ContractInfo; | import com.jd.blockchain.ledger.ContractInfo; | ||||
import com.jd.blockchain.ledger.MerkleProof; | import com.jd.blockchain.ledger.MerkleProof; | ||||
@@ -44,16 +44,16 @@ public class ContractAccount implements ContractInfo { | |||||
} | } | ||||
public long setChaincode(byte[] chaincode, long version) { | 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() { | public byte[] getChainCode() { | ||||
return accBase.getBytes(CHAIN_CODE_KEY).getValue().toBytes(); | |||||
return accBase.getValue(CHAIN_CODE_KEY).getValue().toBytes(); | |||||
} | } | ||||
public byte[] getChainCode(long version) { | 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() { | public long getChaincodeVersion() { | ||||
@@ -61,18 +61,18 @@ public class ContractAccount implements ContractInfo { | |||||
} | } | ||||
public long setProperty(Bytes key, String value, long version) { | 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) { | 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) { | 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) { | 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.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
import com.jd.blockchain.ledger.KVDataObject; | import com.jd.blockchain.ledger.KVDataObject; | ||||
@@ -67,7 +67,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||||
* return -1; | * return -1; | ||||
*/ | */ | ||||
public long setBytes(Bytes key, BytesValue value, long version) { | 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; | * return -1; | ||||
*/ | */ | ||||
public long setBytes(Bytes key, String value, long version) { | 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; | * return -1; | ||||
*/ | */ | ||||
public long setBytes(Bytes key, byte[] value, long version) { | 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; | * @return return null if not exist; | ||||
*/ | */ | ||||
public BytesValue getBytes(String key) { | 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; | * @return return null if not exist; | ||||
*/ | */ | ||||
public BytesValue getBytes(Bytes key) { | 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; | * @return return null if not exist; | ||||
*/ | */ | ||||
public BytesValue getBytes(String key, long version) { | 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; | * @return return null if not exist; | ||||
*/ | */ | ||||
public BytesValue getBytes(Bytes key, long version) { | 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 | * @return | ||||
*/ | */ | ||||
public KVDataEntry getDataEntry(Bytes key, long version) { | public KVDataEntry getDataEntry(Bytes key, long version) { | ||||
BytesValue value = baseAccount.getBytes(key, version); | |||||
BytesValue value = baseAccount.getValue(key, version); | |||||
if (value == null) { | if (value == null) { | ||||
return new KVDataObject(key.toUTF8String(), -1, null); | return new KVDataObject(key.toUTF8String(), -1, null); | ||||
}else { | }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.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | |||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | 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.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.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | 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 | * @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> | * 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 | * Note that, the blockchain identity of the account is not stored in the | ||||
* account's merkle dataset, but is stored by the outer invoker; | * 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 exStorage | ||||
* @param verStorage | * @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) { | 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 | * 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 cryptoSetting | ||||
* @param keyPrefix | |||||
* @param exStorage | * @param exStorage | ||||
* @param verStorage | * @param verStorage | ||||
* @param readonly | * @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); | 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() { | public Bytes getAddress() { | ||||
return bcid.getAddress(); | |||||
return accountID.getAddress(); | |||||
} | } | ||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see com.jd.blockchain.ledger.core.AccountDataSet#getPubKey() | |||||
*/ | |||||
@Override | |||||
public PubKey getPubKey() { | 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 | @Override | ||||
public HashDigest getRootHash() { | public HashDigest getRootHash() { | ||||
return dataset.getRootHash(); | |||||
return rootDS.getRootHash(); | |||||
} | } | ||||
@Override | @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 | * @return | ||||
*/ | */ | ||||
public boolean isReadonly() { | 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 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 | @Override | ||||
public boolean isUpdated() { | public boolean isUpdated() { | ||||
return dataset.isUpdated(); | |||||
return dataDS.getDataset().isUpdated() || headerDS.getDataset().isUpdated() || rootDS.isUpdated(); | |||||
} | } | ||||
@Override | @Override | ||||
public void commit() { | public void commit() { | ||||
dataset.commit(); | |||||
dataDS.getDataset().commit(); | |||||
headerDS.getDataset().commit(); | |||||
rootDS.setValue(key, value, version) | |||||
baseDS.commit(); | |||||
} | } | ||||
@Override | @Override | ||||
public void cancel() { | 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.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.AccountHeader; | import com.jd.blockchain.ledger.AccountHeader; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||||
import com.jd.blockchain.ledger.BytesValue; | import com.jd.blockchain.ledger.BytesValue; | ||||
import com.jd.blockchain.ledger.CryptoSetting; | import com.jd.blockchain.ledger.CryptoSetting; | ||||
import com.jd.blockchain.ledger.LedgerException; | 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.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.RegionMap; | |||||
import com.jd.blockchain.utils.Transactional; | 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 { | static { | ||||
DataContractRegistry.register(MerkleSnapshot.class); | DataContractRegistry.register(MerkleSnapshot.class); | ||||
DataContractRegistry.register(AccountHeader.class); | DataContractRegistry.register(AccountHeader.class); | ||||
} | } | ||||
private final String keyPrefix; | |||||
private final Bytes keyPrefix; | |||||
/** | |||||
* 账户根哈希的数据集; | |||||
*/ | |||||
private MerkleDataSet merkleDataset; | private MerkleDataSet merkleDataset; | ||||
/** | /** | ||||
@@ -36,7 +44,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
* | * | ||||
*/ | */ | ||||
// TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; | // TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; | ||||
private Map<Bytes, InnerVersioningAccount> latestAccountsCache = new HashMap<>(); | |||||
private Map<Bytes, InnerMerkleAccount> latestAccountsCache = new HashMap<>(); | |||||
private ExPolicyKVStorage baseExStorage; | private ExPolicyKVStorage baseExStorage; | ||||
@@ -44,7 +52,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
private CryptoSetting cryptoSetting; | private CryptoSetting cryptoSetting; | ||||
private boolean updated; | |||||
private volatile boolean updated; | |||||
private AccountAccessPolicy accessPolicy; | private AccountAccessPolicy accessPolicy; | ||||
@@ -56,12 +64,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
merkleDataset.setReadonly(); | merkleDataset.setReadonly(); | ||||
} | } | ||||
public MerkleAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage exStorage, | |||||
public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, | |||||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | ||||
this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, 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, | ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | ||||
AccountAccessPolicy accessPolicy) { | AccountAccessPolicy accessPolicy) { | ||||
this.keyPrefix = keyPrefix; | this.keyPrefix = keyPrefix; | ||||
@@ -70,6 +78,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
this.baseVerStorage = verStorage; | this.baseVerStorage = verStorage; | ||||
this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, | this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, | ||||
this.baseVerStorage, readonly); | this.baseVerStorage, readonly); | ||||
this.accessPolicy = accessPolicy; | this.accessPolicy = accessPolicy; | ||||
} | } | ||||
@@ -83,10 +92,11 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
return merkleDataset.getProof(key); | 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); | 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++) { | for (int i = 0; i < results.length; i++) { | ||||
accounts[i] = deserialize(results[i]); | accounts[i] = deserialize(results[i]); | ||||
} | } | ||||
@@ -104,8 +114,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
// keyPrefix, baseExStorage, baseVerStorage, true, accessPolicy, accInfo.); | // 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 | * @param address | ||||
* @return | * @return | ||||
*/ | */ | ||||
@Override | |||||
public MerkleAccount getAccount(Bytes address) { | public MerkleAccount getAccount(Bytes address) { | ||||
return this.getAccount(address, -1); | return this.getAccount(address, -1); | ||||
} | } | ||||
@@ -157,7 +168,7 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
* @return | * @return | ||||
*/ | */ | ||||
public long getVersion(Bytes address) { | public long getVersion(Bytes address) { | ||||
InnerVersioningAccount acc = latestAccountsCache.get(address); | |||||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||||
if (acc != null) { | if (acc != null) { | ||||
// 已注册尚未提交,也返回 -1; | // 已注册尚未提交,也返回 -1; | ||||
return acc.version == -1 ? 0 : acc.version; | 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) { | public MerkleAccount getAccount(Bytes address, long version) { | ||||
version = version < 0 ? -1 : version; | version = version < 0 ? -1 : version; | ||||
InnerVersioningAccount acc = latestAccountsCache.get(address); | |||||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||||
if (acc != null && version == -1) { | if (acc != null && version == -1) { | ||||
return acc; | return acc; | ||||
} else if (acc != null && acc.version == version) { | } else if (acc != null && acc.version == version) { | ||||
@@ -218,8 +229,9 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
// ExPolicyKVStorage ss = PrefixAppender.prefix(prefix, baseExStorage); | // ExPolicyKVStorage ss = PrefixAppender.prefix(prefix, baseExStorage); | ||||
// VersioningKVStorage vs = PrefixAppender.prefix(prefix, baseVerStorage); | // VersioningKVStorage vs = PrefixAppender.prefix(prefix, baseVerStorage); | ||||
// BaseAccount accDS = deserialize(bytes, cryptoSetting, ss, vs, readonly); | // 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) { | if (!readonly) { | ||||
// cache the latest version witch enable reading and writing; | // cache the latest version witch enable reading and writing; | ||||
// readonly version of account not necessary to be cached; | // readonly version of account not necessary to be cached; | ||||
@@ -239,14 +251,16 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
* @param pubKey 公钥; | * @param pubKey 公钥; | ||||
* @return 注册成功的账户对象; | * @return 注册成功的账户对象; | ||||
*/ | */ | ||||
public MerkleAccount register(Bytes address, PubKey pubKey) { | |||||
public MerkleAccount register(BlockchainIdentity accountId) { | |||||
if (isReadonly()) { | if (isReadonly()) { | ||||
throw new IllegalArgumentException("This AccountSet is readonly!"); | throw new IllegalArgumentException("This AccountSet is readonly!"); | ||||
} | } | ||||
Bytes address = accountId.getAddress(); | |||||
PubKey pubKey = accountId.getPubKey(); | |||||
verifyAddressEncoding(address, pubKey); | verifyAddressEncoding(address, pubKey); | ||||
InnerVersioningAccount cachedAcc = latestAccountsCache.get(address); | |||||
InnerMerkleAccount cachedAcc = latestAccountsCache.get(address); | |||||
if (cachedAcc != null) { | if (cachedAcc != null) { | ||||
if (cachedAcc.version < 0) { | if (cachedAcc.version < 0) { | ||||
// 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; | // 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; | ||||
@@ -272,9 +286,8 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
// BaseAccount accDS = createInstance(address, pubKey, cryptoSetting, | // BaseAccount accDS = createInstance(address, pubKey, cryptoSetting, | ||||
// accExStorage, accVerStorage); | // 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); | latestAccountsCache.put(address, acc); | ||||
updated = true; | 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 | @Override | ||||
@@ -315,16 +332,17 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
return; | return; | ||||
} | } | ||||
try { | try { | ||||
for (InnerVersioningAccount acc : latestAccountsCache.values()) { | |||||
for (InnerMerkleAccount acc : latestAccountsCache.values()) { | |||||
// updated or new created; | // updated or new created; | ||||
if (acc.isUpdated() || acc.version < 0) { | if (acc.isUpdated() || acc.version < 0) { | ||||
// 提交更改,更新哈希; | // 提交更改,更新哈希; | ||||
acc.commit(); | acc.commit(); | ||||
byte[] value = serialize(acc); | 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) { | if (ver < 0) { | ||||
// Update fail; | // 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()]; | Bytes[] addresses = new Bytes[latestAccountsCache.size()]; | ||||
latestAccountsCache.keySet().toArray(addresses); | latestAccountsCache.keySet().toArray(addresses); | ||||
for (Bytes address : addresses) { | for (Bytes address : addresses) { | ||||
InnerVersioningAccount acc = latestAccountsCache.remove(address); | |||||
InnerMerkleAccount acc = latestAccountsCache.remove(address); | |||||
// cancel; | // cancel; | ||||
if (acc.isUpdated()) { | if (acc.isUpdated()) { | ||||
acc.cancel(); | acc.cancel(); | ||||
@@ -352,108 +370,24 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ | |||||
updated = false; | 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 | @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; | package com.jd.blockchain.ledger.core; | ||||
import com.jd.blockchain.ledger.MerkleProof; | 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 { | public interface MerkleDataEntry { | ||||
VersioningKVEntry getData(); | |||||
VersioningKVEntry<Bytes, byte[]> getData(); | |||||
MerkleProof getProof(); | MerkleProof getProof(); | ||||
} | } |
@@ -7,12 +7,13 @@ import com.jd.blockchain.ledger.MerkleDataNode; | |||||
import com.jd.blockchain.ledger.MerkleProof; | import com.jd.blockchain.ledger.MerkleProof; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | 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.VersioningKVStorage; | ||||
import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | import com.jd.blockchain.storage.service.utils.BufferedKVStorage; | ||||
import com.jd.blockchain.storage.service.utils.VersioningKVData; | import com.jd.blockchain.storage.service.utils.VersioningKVData; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | 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; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
/** | /** | ||||
@@ -23,7 +24,7 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
public class MerkleDataSet implements Transactional, MerkleProvable, VersioningMap<Bytes, byte[]> { | |||||
/** | /** | ||||
* 4 MB MaxSize of value; | * 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 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 snKeyPrefix; | ||||
private final Bytes dataKeyPrefix; | private final Bytes dataKeyPrefix; | ||||
@@ -102,19 +103,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
* @param merkleTreeStorage | * @param merkleTreeStorage | ||||
* @param snGenerator | * @param snGenerator | ||||
*/ | */ | ||||
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, String keyPrefix, | |||||
public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, Bytes keyPrefix, | |||||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | ||||
// 缓冲对KV的写入; | // 缓冲对KV的写入; | ||||
this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | ||||
// 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击; | // 把存储数据值、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.valueStorage = bufferedStorage; | ||||
this.snStorage = bufferedStorage; | this.snStorage = bufferedStorage; | ||||
// MerkleTree 本身是可缓冲的; | // MerkleTree 本身是可缓冲的; | ||||
merkleKeyPrefix = Bytes.fromString(keyPrefix + MERKLE_TREE_PREFIX); | |||||
merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); | |||||
ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | ||||
this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly); | this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly); | ||||
@@ -154,20 +157,21 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
return values; | return values; | ||||
} | } | ||||
public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) { | |||||
public VersioningKVEntry<Bytes, byte[]>[] getLatestDataEntries(int fromIndex, int count) { | |||||
if (count > LedgerConsts.MAX_LIST_COUNT) { | if (count > LedgerConsts.MAX_LIST_COUNT) { | ||||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | ||||
} | } | ||||
if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | ||||
throw new IllegalArgumentException("Index out of bound!"); | throw new IllegalArgumentException("Index out of bound!"); | ||||
} | } | ||||
VersioningKVEntry[] values = new VersioningKVEntry[count]; | |||||
@SuppressWarnings("unchecked") | |||||
VersioningKVEntry<Bytes, byte[]>[] values = new VersioningKVEntry[count]; | |||||
byte[] bytesValue; | byte[] bytesValue; | ||||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||||
MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | ||||
Bytes dataKey = encodeDataKey(dataNode.getKey()); | Bytes dataKey = encodeDataKey(dataNode.getKey()); | ||||
bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); | 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; | return values; | ||||
} | } | ||||
@@ -192,32 +196,34 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
*/ | */ | ||||
public String getKeyAtIndex(int fromIndex) { | public String getKeyAtIndex(int fromIndex) { | ||||
MerkleDataNode dataNode = merkleTree.getData(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 | * 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 | * If this operation fail by version checking or other reason, then | ||||
* return -1; | * return -1; | ||||
*/ | */ | ||||
@Override | |||||
public long setValue(Bytes key, byte[] value, long version) { | public long setValue(Bytes key, byte[] value, long version) { | ||||
if (readonly) { | if (readonly) { | ||||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | throw new IllegalArgumentException("This merkle dataset is readonly!"); | ||||
@@ -336,18 +343,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
return mdn.getVersion(); | 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> | * Return the specified version's value;<br> | ||||
@@ -358,6 +366,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
* @param key | * @param key | ||||
* @param version | * @param version | ||||
*/ | */ | ||||
@Override | |||||
public byte[] getValue(Bytes key, long version) { | public byte[] getValue(Bytes key, long version) { | ||||
long latestVersion = getMerkleVersion(key); | long latestVersion = getMerkleVersion(key); | ||||
if (latestVersion < 0 || version > latestVersion) { | if (latestVersion < 0 || version > latestVersion) { | ||||
@@ -370,15 +379,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
return valueStorage.get(dataKey, version); | 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; | * Return the latest version's value; | ||||
@@ -386,6 +396,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
* @param key | * @param key | ||||
* @return return null if not exist; | * @return return null if not exist; | ||||
*/ | */ | ||||
@Override | |||||
public byte[] getValue(Bytes key) { | public byte[] getValue(Bytes key) { | ||||
long latestVersion = getMerkleVersion(key); | long latestVersion = getMerkleVersion(key); | ||||
if (latestVersion < 0) { | if (latestVersion < 0) { | ||||
@@ -395,16 +406,17 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
return valueStorage.get(dataKey, latestVersion); | 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 | * Return the latest version entry associated the specified key; If the key | ||||
@@ -413,20 +425,22 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
* @param key | * @param key | ||||
* @return | * @return | ||||
*/ | */ | ||||
@Override | |||||
public long getVersion(Bytes key) { | public long getVersion(Bytes key) { | ||||
return getMerkleVersion(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 | * @param key | ||||
* @return Null if the key doesn't exist! | * @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); | long latestVersion = getMerkleVersion(key); | ||||
if (latestVersion < 0) { | if (latestVersion < 0) { | ||||
return null; | return null; | ||||
@@ -436,10 +450,11 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
if (value == null) { | if (value == null) { | ||||
return 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); | long latestVersion = getMerkleVersion(key); | ||||
if (latestVersion < 0 || version > latestVersion) { | if (latestVersion < 0 || version > latestVersion) { | ||||
// key not exist, or the specified version is out of the latest version indexed | // 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) { | if (value == null) { | ||||
return null; | return null; | ||||
} | } | ||||
return new VersioningKVData(key, version, value); | |||||
return new VersioningKVData<Bytes, byte[]>(key, version, value); | |||||
} | } | ||||
public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | ||||
VersioningKVEntry dataEntry = getDataEntry(key, version); | |||||
VersioningKVEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version); | |||||
if (dataEntry == null) { | if (dataEntry == null) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -465,7 +480,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
} | } | ||||
public MerkleDataEntry getMerkleEntry(Bytes key) { | public MerkleDataEntry getMerkleEntry(Bytes key) { | ||||
VersioningKVEntry dataEntry = getDataEntry(key); | |||||
VersioningKVEntry<Bytes, byte[]> dataEntry = getDataEntry(key); | |||||
if (dataEntry == null) { | if (dataEntry == null) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -499,16 +514,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
*/ | */ | ||||
private static class MerkleDataEntryWrapper implements MerkleDataEntry { | private static class MerkleDataEntryWrapper implements MerkleDataEntry { | ||||
private VersioningKVEntry data; | |||||
private VersioningKVEntry<Bytes, byte[]> data; | |||||
private MerkleProof proof; | private MerkleProof proof; | ||||
public MerkleDataEntryWrapper(VersioningKVEntry data, MerkleProof proof) { | |||||
public MerkleDataEntryWrapper(VersioningKVEntry<Bytes, byte[]> data, MerkleProof proof) { | |||||
this.data = data; | this.data = data; | ||||
this.proof = proof; | this.proof = proof; | ||||
} | } | ||||
@Override | @Override | ||||
public VersioningKVEntry getData() { | |||||
public VersioningKVEntry<Bytes, byte[]> getData() { | |||||
return data; | return data; | ||||
} | } | ||||
@@ -14,10 +14,10 @@ import com.jd.blockchain.ledger.RolePrivileges; | |||||
import com.jd.blockchain.ledger.TransactionPermission; | import com.jd.blockchain.ledger.TransactionPermission; | ||||
import com.jd.blockchain.ledger.TransactionPrivilege; | import com.jd.blockchain.ledger.TransactionPrivilege; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
public class RolePrivilegeDataset implements Transactional, MerkleProvable, RolePrivilegeSettings { | 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.HashDigest; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.TypedBytesValue; | |||||
import com.jd.blockchain.ledger.BytesValue; | 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.Bytes; | ||||
import com.jd.blockchain.utils.VersioningMap; | |||||
/** | /** | ||||
* 用户账户; | * 用户账户; | ||||
@@ -13,35 +14,20 @@ import com.jd.blockchain.utils.Bytes; | |||||
* @author huanghaiquan | * @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 USER_INFO_PREFIX = Bytes.fromString("PROP" + LedgerConsts.KEY_SEPERATOR); | ||||
private static final Bytes DATA_PUB_KEY = Bytes.fromString("DATA-PUBKEY"); | 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; | this.baseAccount = baseAccount; | ||||
} | } | ||||
public PubKey getDataPubKey() { | public PubKey getDataPubKey() { | ||||
BytesValue pkBytes = baseAccount.getBytes(DATA_PUB_KEY); | |||||
BytesValue pkBytes = baseAccount.getValue(DATA_PUB_KEY); | |||||
if (pkBytes == null) { | if (pkBytes == null) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -50,12 +36,12 @@ public class UserAccount implements UserInfo { | |||||
public long setDataPubKey(PubKey pubKey) { | public long setDataPubKey(PubKey pubKey) { | ||||
byte[] pkBytes = pubKey.toBytes(); | 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) { | public long setDataPubKey(PubKey pubKey, long version) { | ||||
byte[] pkBytes = pubKey.toBytes(); | 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) { | 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) { | 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) { | public String getProperty(Bytes key) { | ||||
BytesValue value = baseAccount.getBytes(encodePropertyKey(key)); | |||||
BytesValue value = baseAccount.getValue(encodePropertyKey(key)); | |||||
return value == null ? null : value.getValue().toUTF8String(); | return value == null ? null : value.getValue().toUTF8String(); | ||||
} | } | ||||
public String getProperty(Bytes key, long version) { | 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(); | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
import com.jd.blockchain.utils.VersioningMap; | |||||
/** | /** | ||||
* @author huanghaiquan | * @author huanghaiquan | ||||
@@ -71,7 +72,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||||
@Override | @Override | ||||
public UserAccount getAccount(Bytes address) { | public UserAccount getAccount(Bytes address) { | ||||
MerkleAccount baseAccount = accountSet.getAccount(address); | |||||
VersioningMap baseAccount = accountSet.getAccount(address); | |||||
return new UserAccount(baseAccount); | return new UserAccount(baseAccount); | ||||
} | } | ||||
@@ -82,7 +83,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||||
@Override | @Override | ||||
public UserAccount getAccount(Bytes address, long version) { | public UserAccount getAccount(Bytes address, long version) { | ||||
MerkleAccount baseAccount = accountSet.getAccount(address, version); | |||||
VersioningMap baseAccount = accountSet.getAccount(address, version); | |||||
return new UserAccount(baseAccount); | return new UserAccount(baseAccount); | ||||
} | } | ||||
@@ -100,7 +101,7 @@ public class UserAccountSet implements Transactional, UserAccountQuery { | |||||
* @return 注册成功的用户对象; | * @return 注册成功的用户对象; | ||||
*/ | */ | ||||
public UserAccount register(Bytes address, PubKey pubKey) { | public UserAccount register(Bytes address, PubKey pubKey) { | ||||
MerkleAccount baseAccount = accountSet.register(address, pubKey); | |||||
VersioningMap baseAccount = accountSet.register(address, pubKey); | |||||
return new UserAccount(baseAccount); | 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.UserRoles; | ||||
import com.jd.blockchain.ledger.UserAuthorizationSettings; | import com.jd.blockchain.ledger.UserAuthorizationSettings; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
/** | /** | ||||
* User-Role authorization data set; | * User-Role authorization data set; | ||||
@@ -268,7 +268,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -276,7 +276,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -284,7 +284,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -301,7 +301,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -309,7 +309,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -317,7 +317,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -325,7 +325,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | return this; | ||||
@@ -333,7 +333,7 @@ public class ContractLedgerContext implements LedgerContext { | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | 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); | this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | ||||
handle(op); | handle(op); | ||||
return this; | 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.crypto.service.sm.SMCryptoService; | ||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.BytesData; | |||||
import com.jd.blockchain.ledger.TypedBytesValue; | |||||
import com.jd.blockchain.ledger.core.MerkleAccount; | import com.jd.blockchain.ledger.core.MerkleAccount; | ||||
import com.jd.blockchain.ledger.core.CryptoConfig; | import com.jd.blockchain.ledger.core.CryptoConfig; | ||||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | ||||
@@ -53,33 +53,33 @@ public class BaseAccountTest { | |||||
assertFalse(baseAccount.isReadonly()); | 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); | 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); | 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); | 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,预期导致失败; | // 已经存在版本,指定版本号-1,预期导致失败; | ||||
assertEquals(-1, v); | assertEquals(-1, v); | ||||
baseAccount.commit(); | baseAccount.commit(); | ||||
v = 0; | v = 0; | ||||
for (int i = 0; i < 10; i++) { | 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(); | baseAccount.commit(); | ||||
// 预期成功; | // 预期成功; | ||||
assertEquals(v + 1, s); | assertEquals(v + 1, s); | ||||
v++; | 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); | assertEquals(-1, v); | ||||
@@ -132,7 +132,7 @@ public class ContractInvokingTest { | |||||
assertEquals(1, opResults.length); | assertEquals(1, opResults.length); | ||||
assertEquals(0, opResults[0].getIndex()); | 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); | byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); | ||||
assertArrayEquals(expectedRetnBytes, reallyRetnBytes); | assertArrayEquals(expectedRetnBytes, reallyRetnBytes); | ||||
@@ -218,7 +218,7 @@ public class ContractInvokingTest { | |||||
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); | TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); | ||||
txResultHandle.commit(); | txResultHandle.commit(); | ||||
BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getBytes(key, | |||||
BytesValue latestValue = ledgerRepo.getDataAccountSet().getAccount(kpDataAccount.getAddress()).getValue(key, | |||||
-1); | -1); | ||||
System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getValue().toUTF8String()); | System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.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.MerkleProof; | ||||
import com.jd.blockchain.ledger.core.CryptoConfig; | import com.jd.blockchain.ledger.core.CryptoConfig; | ||||
import com.jd.blockchain.ledger.core.MerkleDataSet; | 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.storage.service.utils.MemoryKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
public class MerkleDataSetTest { | public class MerkleDataSetTest { | ||||
@@ -332,13 +332,13 @@ public class TransactionBatchProcessorTest { | |||||
newBlock = newBlockEditor.prepare(); | newBlock = newBlockEditor.prepare(); | ||||
newBlockEditor.commit(); | newBlockEditor.commit(); | ||||
BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", | |||||
BytesValue v1_0 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K1", | |||||
0); | 0); | ||||
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K1", | |||||
BytesValue v1_1 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K1", | |||||
1); | 1); | ||||
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K2", | |||||
BytesValue v2 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K2", | |||||
0); | 0); | ||||
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getBytes("K3", | |||||
BytesValue v3 = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()).getValue("K3", | |||||
0); | 0); | ||||
assertNotNull(v1_0); | assertNotNull(v1_0); | ||||
@@ -376,8 +376,8 @@ public class TransactionBatchProcessorTest { | |||||
newBlock = newBlockEditor.prepare(); | newBlock = newBlockEditor.prepare(); | ||||
newBlockEditor.commit(); | 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,没有更新; | // k1 的版本仍然为1,没有更新; | ||||
long k1_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) | long k1_version = ledgerRepo.getDataAccountSet().getAccount(dataAccountKeypair.getAddress()) | ||||
@@ -8,7 +8,7 @@ import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@DataContract(code= DataCodes.ACCOUNT_HEADER) | @DataContract(code= DataCodes.ACCOUNT_HEADER) | ||||
public interface AccountHeader extends MerkleSnapshot{ | |||||
public interface AccountHeader { //extends MerkleSnapshot{ | |||||
@DataField(order=1, primitiveType = PrimitiveType.BYTES) | @DataField(order=1, primitiveType = PrimitiveType.BYTES) | ||||
Bytes getAddress(); | 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) { | public static BytesValueList singleText(String value) { | ||||
return new BytesDataList(BytesData.fromText(value)); | |||||
return new BytesDataList(TypedBytesValue.fromText(value)); | |||||
} | } | ||||
public static BytesValueList singleLong(long 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) { | public static BytesValueList singleInt(int value) { | ||||
return new BytesDataList(BytesData.fromInt32(value)); | |||||
return new BytesDataList(TypedBytesValue.fromInt32(value)); | |||||
} | } | ||||
public static BytesValueList singleBoolean(boolean 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); | 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); | BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type); | ||||
if (bytesValueResolver == null) { | if (bytesValueResolver == null) { | ||||
@@ -106,6 +106,20 @@ public enum DataType { | |||||
* DataContract 数据; | * DataContract 数据; | ||||
*/ | */ | ||||
DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); | 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) | @EnumField(type = PrimitiveType.INT8) | ||||
public final byte CODE; | public final byte CODE; | ||||
@@ -114,6 +128,51 @@ public enum DataType { | |||||
this.CODE = code; | 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) { | public static DataType valueOf(byte code) { | ||||
for (DataType dataType : DataType.values()) { | for (DataType dataType : DataType.values()) { | ||||
if (dataType.CODE == code) { | 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; | 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(); | 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 | // * @return | ||||
// * | |||||
// * @see MerkleTree#getLevel() | |||||
// */ | // */ | ||||
// long getStartingSN(int level); | |||||
// int getLevels(); | |||||
// | |||||
// /** | // /** | ||||
// * 返回证明中指定层级的数据记录总数; | |||||
// * 返回证明中指定层级的节点的哈希; | |||||
// * <p> | |||||
// * | // * | ||||
// * @param level | // * @param level | ||||
// * 参数值为 0 返回的是数据节点的哈希; <br> | |||||
// * 参数值为 {@link #getLevels()} 返回的是根节点的哈希; | |||||
// * @return | // * @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() { | default MerkleDataNode getDataNode() { | ||||
return (MerkleDataNode)getNode(0); | 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.binaryproto.DataContract; | ||||
import com.jd.blockchain.consts.DataCodes; | 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; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -21,7 +21,7 @@ public class BooleanToBytesValueResolver extends AbstractBytesValueResolver { | |||||
if (!isSupport(type)) { | if (!isSupport(type)) { | ||||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | ||||
} | } | ||||
return BytesData.fromBoolean((boolean) value); | |||||
return TypedBytesValue.fromBoolean((boolean) value); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -1,6 +1,6 @@ | |||||
package com.jd.blockchain.ledger.resolver; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | 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())); | throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | ||||
} | } | ||||
if (type.equals(byte[].class)) { | 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 | @Override | ||||
@@ -1,6 +1,6 @@ | |||||
package com.jd.blockchain.ledger.resolver; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -21,7 +21,7 @@ public class IntegerToBytesValueResolver extends AbstractBytesValueResolver { | |||||
if (!isSupport(type)) { | if (!isSupport(type)) { | ||||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | ||||
} | } | ||||
return BytesData.fromInt32((int) value); | |||||
return TypedBytesValue.fromInt32((int) value); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -1,6 +1,6 @@ | |||||
package com.jd.blockchain.ledger.resolver; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -21,7 +21,7 @@ public class LongToBytesValueResolver extends AbstractBytesValueResolver { | |||||
if (!isSupport(type)) { | if (!isSupport(type)) { | ||||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | ||||
} | } | ||||
return BytesData.fromInt64((long)value); | |||||
return TypedBytesValue.fromInt64((long)value); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -1,6 +1,6 @@ | |||||
package com.jd.blockchain.ledger.resolver; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -21,7 +21,7 @@ public class ShortToBytesValueResolver extends AbstractBytesValueResolver { | |||||
if (!isSupport(type)) { | if (!isSupport(type)) { | ||||
throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | ||||
} | } | ||||
return BytesData.fromInt16((short)value); | |||||
return TypedBytesValue.fromInt16((short)value); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -1,6 +1,6 @@ | |||||
package com.jd.blockchain.ledger.resolver; | 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.BytesValue; | ||||
import com.jd.blockchain.ledger.DataType; | import com.jd.blockchain.ledger.DataType; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -26,10 +26,10 @@ public class StringToBytesValueResolver extends AbstractBytesValueResolver { | |||||
// 类型判断 | // 类型判断 | ||||
String valString = (String)value; | String valString = (String)value; | ||||
if (JSONSerializeUtils.isJSON(valString)) { | if (JSONSerializeUtils.isJSON(valString)) { | ||||
return BytesData.fromJSON(valString); | |||||
return TypedBytesValue.fromJSON(valString); | |||||
} | } | ||||
// 暂不处理XML格式 | // 暂不处理XML格式 | ||||
return BytesData.fromText(valString); | |||||
return TypedBytesValue.fromText(valString); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -1,7 +1,7 @@ | |||||
package com.jd.blockchain.transaction; | package com.jd.blockchain.transaction; | ||||
import com.jd.blockchain.ledger.BytesValue; | 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.ledger.DataAccountKVSetOperation; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromBytes(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromImage(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromImage(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromText(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromText(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromBytes(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromBytes(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromInt64(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromInt64(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromJSON(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromJSON(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromXML(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromXML(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | ||||
BytesValue bytesValue = BytesData.fromTimestamp(value); | |||||
BytesValue bytesValue = TypedBytesValue.fromTimestamp(value); | |||||
operation.set(key, bytesValue, expVersion); | operation.set(key, bytesValue, expVersion); | ||||
return this; | return this; | ||||
} | } | ||||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | 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.BytesDataList; | ||||
import com.jd.blockchain.ledger.BytesValueList; | import com.jd.blockchain.ledger.BytesValueList; | ||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | import com.jd.blockchain.ledger.ContractEventSendOperation; | ||||
@@ -41,7 +41,7 @@ public class ContractEventSendOpTemplateTest { | |||||
DataContractRegistry.register(ContractEventSendOperation.class); | DataContractRegistry.register(ContractEventSendOperation.class); | ||||
DataContractRegistry.register(Operation.class); | DataContractRegistry.register(Operation.class); | ||||
String contractAddress = "zhangsan-address", event = "zhangsan-event"; | 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); | 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.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | 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.DataAccountKVSetOperation; | ||||
import com.jd.blockchain.ledger.Operation; | import com.jd.blockchain.ledger.Operation; | ||||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | ||||
@@ -41,11 +41,11 @@ public class DataAccountKVSetOpTemplateTest { | |||||
String accountAddress = "zhangsandhakhdkah"; | String accountAddress = "zhangsandhakhdkah"; | ||||
data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); | data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); | ||||
KVData kvData1 = | KVData kvData1 = | ||||
new KVData("test1", BytesData.fromText("zhangsan"), 9999L); | |||||
new KVData("test1", TypedBytesValue.fromText("zhangsan"), 9999L); | |||||
KVData kvData2 = | KVData kvData2 = | ||||
new KVData("test2", BytesData.fromText("lisi"), 9990L); | |||||
new KVData("test2", TypedBytesValue.fromText("lisi"), 9990L); | |||||
KVData kvData3 = | KVData kvData3 = | ||||
new KVData("test3", BytesData.fromText("wangwu"), 1990L); | |||||
new KVData("test3", TypedBytesValue.fromText("wangwu"), 1990L); | |||||
data.set(kvData1); | data.set(kvData1); | ||||
data.set(kvData2); | data.set(kvData2); | ||||
data.set(kvData3); | data.set(kvData3); | ||||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | 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.DataAccountKVSetOperation; | ||||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | ||||
import com.jd.blockchain.transaction.KVData; | import com.jd.blockchain.transaction.KVData; | ||||
@@ -38,7 +38,7 @@ public class KVDataTest { | |||||
byte[] value = "test-value".getBytes(); | byte[] value = "test-value".getBytes(); | ||||
long expectedVersion = 9999L; | long expectedVersion = 9999L; | ||||
kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); | |||||
kvData = new KVData(key, TypedBytesValue.fromBytes(value), expectedVersion); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -151,7 +151,7 @@ public class ClientResolveUtil { | |||||
String realValBase58 = valueObj.getJSONObject("value").getString("value"); | String realValBase58 = valueObj.getJSONObject("value").getString("value"); | ||||
String key = currWriteSetObj.getString("key"); | String key = currWriteSetObj.getString("key"); | ||||
DataType dataType = DataType.valueOf(typeStr); | 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); | KVData kvData = new KVData(key, bytesValue, expectedVersion); | ||||
kvOperation.set(kvData); | kvOperation.set(kvData); | ||||
} | } | ||||
@@ -200,7 +200,7 @@ public class ClientResolveUtil { | |||||
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | ||||
String pubKeyBase58 = pubKeyObj.getString("value"); | String pubKeyBase58 = pubKeyObj.getString("value"); | ||||
// 生成ParticipantNode对象 | // 生成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; | participantNodes[i] = participantCertData; | ||||
} | } | ||||
ledgerInitSettingData.setConsensusParticipants(participantNodes); | ledgerInitSettingData.setConsensusParticipants(participantNodes); | ||||
@@ -294,11 +294,12 @@ public class ClientResolveUtil { | |||||
this.pubKey = participantNode.getPubKey(); | 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.id = id; | ||||
this.address = address; | this.address = address; | ||||
this.name = name; | this.name = name; | ||||
this.pubKey = pubKey; | this.pubKey = pubKey; | ||||
this.participantNodeState = participantNodeState; | this.participantNodeState = participantNodeState; | ||||
} | } | ||||
@@ -1,8 +1,8 @@ | |||||
package com.jd.blockchain.storage.service.impl.redis; | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
import redis.clients.jedis.Jedis; | import redis.clients.jedis.Jedis; | ||||
import redis.clients.jedis.JedisPool; | import redis.clients.jedis.JedisPool; | ||||
@@ -7,9 +7,9 @@ import java.util.concurrent.locks.ReentrantLock; | |||||
import org.apache.commons.collections4.map.LRUMap; | import org.apache.commons.collections4.map.LRUMap; | ||||
import org.rocksdb.*; | import org.rocksdb.*; | ||||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
import com.jd.blockchain.utils.io.BytesUtils; | 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; | package com.jd.blockchain.storage.service; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
/** | /** | ||||
* Versioning Key-Value Storage | * Versioning Key-Value Storage | ||||
@@ -40,7 +41,7 @@ public interface VersioningKVStorage extends BatchStorageService { | |||||
* @param version | * @param version | ||||
* @return | * @return | ||||
*/ | */ | ||||
VersioningKVEntry getEntry(Bytes key, long version); | |||||
VersioningKVEntry<Bytes, byte[]> getEntry(Bytes key, long version); | |||||
/** | /** | ||||
* Return the specified verson's value; <br> | * Return the specified verson's value; <br> | ||||
@@ -7,10 +7,10 @@ import java.util.concurrent.ForkJoinTask; | |||||
import java.util.concurrent.RecursiveTask; | import java.util.concurrent.RecursiveTask; | ||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.Transactional; | import com.jd.blockchain.utils.Transactional; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
/** | /** | ||||
* {@link BufferedKVStorage} 缓冲写入的KV存储;<br> | * {@link BufferedKVStorage} 缓冲写入的KV存储;<br> | ||||
@@ -77,9 +77,9 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage | |||||
} | } | ||||
return ws.getLatestVersion(); | return ws.getLatestVersion(); | ||||
} | } | ||||
@Override | @Override | ||||
public VersioningKVEntry getEntry(Bytes key, long version) { | |||||
public VersioningKVEntry<Bytes, byte[]> getEntry(Bytes key, long version) { | |||||
VersioningWritingSet ws = versioningCache.get(key); | VersioningWritingSet ws = versioningCache.get(key); | ||||
if (ws == null) { | if (ws == null) { | ||||
return origVersioningStorage.getEntry(key, version); | return origVersioningStorage.getEntry(key, version); | ||||
@@ -484,7 +484,7 @@ public class BufferedKVStorage implements VersioningKVStorage, ExPolicyKVStorage | |||||
return startingVersion; | return startingVersion; | ||||
} | } | ||||
public VersioningKVEntry getEntry(long version) { | |||||
public VersioningKVEntry<Bytes, byte[]> getEntry(long version) { | |||||
byte[] value = get(version); | byte[] value = get(version); | ||||
if (value == null) { | if (value == null) { | ||||
return 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; | private Bytes key; | ||||
@@ -5,9 +5,9 @@ import java.util.Set; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | import com.jd.blockchain.storage.service.ExPolicyKVStorage; | ||||
import com.jd.blockchain.storage.service.KVStorageService; | 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.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
import com.jd.blockchain.utils.io.BytesMap; | import com.jd.blockchain.utils.io.BytesMap; | ||||
public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap<Bytes> { | public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap<Bytes> { | ||||
@@ -1,24 +1,23 @@ | |||||
package com.jd.blockchain.storage.service.utils; | 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 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.key = key; | ||||
this.version = version; | this.version = version; | ||||
this.value = value; | this.value = value; | ||||
} | } | ||||
@Override | @Override | ||||
public Bytes getKey() { | |||||
public K getKey() { | |||||
return key; | return key; | ||||
} | } | ||||
@@ -28,7 +27,7 @@ public class VersioningKVData implements VersioningKVEntry { | |||||
} | } | ||||
@Override | @Override | ||||
public byte[] getValue() { | |||||
public V getValue() { | |||||
return value; | return value; | ||||
} | } | ||||
@@ -5,9 +5,9 @@ import java.util.Map; | |||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | import com.jd.blockchain.storage.service.VersioningKVStorage; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.VersioningKVEntry; | |||||
import com.jd.blockchain.utils.io.BytesMap; | import com.jd.blockchain.utils.io.BytesMap; | ||||
public class VersioningKVStorageMap implements VersioningKVStorage, BytesMap<Bytes> { | 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); | |||||
} |