Browse Source

Fixed bugs: (1)unsupported no-parameter contract function; (2) doesn't rollback when kv-writting version conflict occurs;

tags/1.1.0
huanghaiquan 5 years ago
parent
commit
ef6c4049d2
14 changed files with 435 additions and 29 deletions
  1. +94
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
  2. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java
  3. +6
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java
  4. +169
    -3
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  5. +19
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/KeyValueEntry.java
  6. +47
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/KeyValueObject.java
  7. +33
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/MerkleDataSetTest.java
  8. +10
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
  9. +3
    -6
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContract.java
  10. +6
    -11
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java
  11. +14
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java
  12. +27
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataVersionConflictException.java
  13. +5
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
  14. +1
    -1
      source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java

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

@@ -1,12 +1,11 @@
package com.jd.blockchain.ledger.core;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.KVDataObject;
import com.jd.blockchain.utils.Bytes;
@@ -43,16 +42,85 @@ public class DataAccount implements AccountHeader, MerkleProvable {
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, BytesValue value, long version) {
return baseAccount.setBytes(key, value, version);
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, String value, long version) {
BytesValue bytesValue = BytesData.fromText(value);
return baseAccount.setBytes(key, bytesValue, version);
}
/**
* Create or update the value associated the specified key if the version
* checking is passed.<br>
*
* The value of the key will be updated only if it's latest version equals the
* specified version argument. <br>
* If the key doesn't exist, the version checking will be ignored, and key will
* be created with a new sequence number as id. <br>
* It also could specify the version argument to -1 to ignore the version
* checking.
* <p>
* If updating is performed, the version of the key increase by 1. <br>
* If creating is performed, the version of the key initialize by 0. <br>
*
* @param key The key of data;
* @param value The value of data;
* @param version The expected version of the key.
* @return The new version of the key. <br>
* If the key is new created success, then return 0; <br>
* If the key is updated success, then return the new version;<br>
* If this operation fail by version checking or other reason, then
* return -1;
*/
public long setBytes(Bytes key, byte[] value, long version) {
BytesValue bytesValue = BytesData.fromBytes(value);
return baseAccount.setBytes(key, bytesValue, version);
@@ -121,6 +189,29 @@ public class DataAccount implements AccountHeader, MerkleProvable {
public BytesValue getBytes(Bytes key, long version) {
return baseAccount.getBytes(key, version);
}
/**
* @param key
* @param version
* @return
*/
public KVDataEntry getDataEntry(String key, long version) {
return getDataEntry(Bytes.fromString(key), version);
}
/**
* @param key
* @param version
* @return
*/
public KVDataEntry getDataEntry(Bytes key, long version) {
BytesValue value = baseAccount.getBytes(key, version);
if (value == null) {
return new KVDataObject(key.toUTF8String(), -1, null);
}else {
return new KVDataObject(key.toUTF8String(), version, value);
}
}
/**
* return the specified index's KVDataEntry;
@@ -131,7 +222,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
*/
public KVDataEntry[] getDataEntries(int fromIndex, int count) {
if (getDataEntriesTotalCount() == 0 || count == 0) {
if (count == 0 || getDataEntriesTotalCount() == 0) {
return null;
}


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

@@ -168,7 +168,7 @@ public class MerkleDataSet implements Transactional, MerkleProvable {
*/
public String getKeyAtIndex(int fromIndex) {
MerkleDataNode dataNode = merkleTree.getData(fromIndex);
return new String(dataNode.getKey().toBytes());
return dataNode.getKey().toUTF8String();
}


+ 6
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java View File

@@ -7,6 +7,7 @@ import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataAccountDoesNotExistException;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry;
import com.jd.blockchain.ledger.DataVersionConflictException;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.core.DataAccount;
import com.jd.blockchain.ledger.core.LedgerDataSet;
@@ -31,8 +32,12 @@ public class DataAccountKVSetOperationHandle implements OperationHandle {
throw new DataAccountDoesNotExistException("DataAccount doesn't exist!");
}
KVWriteEntry[] writeSet = kvWriteOp.getWriteSet();
long v = -1;
for (KVWriteEntry kvw : writeSet) {
account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion());
v = account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion());
if (v < 0) {
throw new DataVersionConflictException();
}
}
return null;
}


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

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

import static com.jd.blockchain.transaction.ContractReturnValue.decode;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -25,6 +26,7 @@ import com.jd.blockchain.ledger.BytesData;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.EndpointRequest;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInitSetting;
import com.jd.blockchain.ledger.LedgerTransaction;
@@ -40,16 +42,17 @@ import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerEditor;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.LedgerService;
import com.jd.blockchain.ledger.core.LedgerTransactionContext;
import com.jd.blockchain.ledger.core.UserAccount;
import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.ledger.core.impl.LedgerTransactionalEditor;
import com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration;
import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor;
import com.jd.blockchain.service.TransactionBatchResultHandle;
import com.jd.blockchain.storage.service.utils.MemoryKVStorage;
import com.jd.blockchain.transaction.BooleanValueHolder;
import static com.jd.blockchain.transaction.ContractReturnValue.*;
import com.jd.blockchain.transaction.TxBuilder;
import com.jd.blockchain.utils.Bytes;

@@ -152,7 +155,7 @@ public class ContractInvokingTest {

}

@Test
// @Test
public void testReadNewWritting() {
// 初始化账本到指定的存储库;
HashDigest ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3);
@@ -219,7 +222,6 @@ public class ContractInvokingTest {
BytesValue latestValue = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getBytes(key,
-1);
System.out.printf("latest value=[%s] %s \r\n", latestValue.getType(), latestValue.getValue().toUTF8String());

boolean readable = readableHolder.get();
assertTrue(readable);
@@ -230,6 +232,164 @@ public class ContractInvokingTest {
assertEquals(resp1.getBlockHash(), latestBlock.getHash());
}

/**
* 验证在合约方法中写入数据账户时,如果版本校验失败是否会引发异常而导致回滚;<br>
* 期待正确的表现是引发异常而回滚当前交易;
*/
@Test
public void testRollbackWhileVersionConfliction() {
// 初始化账本到指定的存储库;
HashDigest ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3);

// 重新加载账本;
LedgerManager ledgerManager = new LedgerManager();
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);

// 创建合约处理器;
ContractInvokingHandle contractInvokingHandle = new ContractInvokingHandle();

// 创建和加载合约实例;
BlockchainKeypair contractKey = BlockchainKeyGenerator.getInstance().generate();
Bytes contractAddress = contractKey.getAddress();
TxTestContractImpl contractInstance = new TxTestContractImpl();
contractInvokingHandle.setup(contractAddress, TxTestContract.class, contractInstance);

// 注册合约处理器;
DefaultOperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration();
opReg.insertAsTopPriority(contractInvokingHandle);

// 发布指定地址合约
deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey);

// 注册数据账户;
BlockchainKeypair kpDataAccount = BlockchainKeyGenerator.getInstance().generate();
contractInstance.setDataAddress(kpDataAccount.getAddress());
registerDataAccount(ledgerRepo, ledgerManager, opReg, ledgerHash, kpDataAccount);

// 调用合约
// 构建基于接口调用合约的交易请求,用于测试合约调用;
buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() {
@Override
public void buildTx(TxBuilder txBuilder) {
TxTestContract contractProxy = txBuilder.contract(contractAddress, TxTestContract.class);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K1", "V1-0",
-1);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K2", "V2-0",
-1);
}
});
// 预期数据都能够正常写入;
KVDataEntry kv1 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K1",
0);
KVDataEntry kv2 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K2",
0);
assertEquals(0, kv1.getVersion());
assertEquals(0, kv2.getVersion());
assertEquals("V1-0", kv1.getValue());
assertEquals("V2-0", kv2.getValue());

// 构建基于接口调用合约的交易请求,用于测试合约调用;
buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() {
@Override
public void buildTx(TxBuilder txBuilder) {
TxTestContract contractProxy = txBuilder.contract(contractAddress, TxTestContract.class);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K1", "V1-1",
0);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K2", "V2-1",
0);
}
});
// 预期数据都能够正常写入;
kv1 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1);
kv2 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K2", 1);
assertEquals(1, kv1.getVersion());
assertEquals(1, kv2.getVersion());
assertEquals("V1-1", kv1.getValue());
assertEquals("V2-1", kv2.getValue());
// 构建基于接口调用合约的交易请求,用于测试合约调用;
buildBlock(ledgerRepo, ledgerManager, opReg, new TxDefinitor() {
@Override
public void buildTx(TxBuilder txBuilder) {
TxTestContract contractProxy = txBuilder.contract(contractAddress, TxTestContract.class);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K1", "V1-2",
1);
contractProxy.testRollbackWhileVersionConfliction(kpDataAccount.getAddress().toBase58(), "K2", "V2-2",
0);
}
});
// 预期数据都能够正常写入;
kv1 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K1", 1);
assertEquals(1, kv1.getVersion());
assertEquals("V1-1", kv1.getValue());
kv1 = ledgerRepo.getDataAccountSet().getDataAccount(kpDataAccount.getAddress()).getDataEntry("K1", 2);
assertEquals(-1, kv1.getVersion());
assertEquals(null, kv1.getValue());

}

private LedgerBlock buildBlock(LedgerRepository ledgerRepo, LedgerService ledgerService,
OperationHandleRegisteration opReg, TxDefinitor txDefinitor) {
LedgerBlock preBlock = ledgerRepo.getLatestBlock();
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(preBlock);
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
opReg, ledgerService);

TxBuilder txBuilder = new TxBuilder(ledgerRepo.getHash());
txDefinitor.buildTx(txBuilder);

TransactionRequest txReq = buildAndSignRequest(txBuilder, parti0, parti0);
TransactionResponse resp = txbatchProcessor.schedule(txReq);

// 提交区块;
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare();
txResultHandle.commit();

LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
assertNotNull(resp.getBlockHash());
assertEquals(preBlock.getHeight() + 1, resp.getBlockHeight());
return latestBlock;
}

private TransactionRequest buildAndSignRequest(TxBuilder txBuilder, BlockchainKeypair endpointKey,
BlockchainKeypair nodeKey) {
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
txReqBuilder.signAsEndpoint(endpointKey);
txReqBuilder.signAsNode(nodeKey);
TransactionRequest txReq = txReqBuilder.buildRequest();
return txReq;
}

private void registerDataAccount(LedgerRepository ledgerRepo, LedgerManager ledgerManager,
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, BlockchainKeypair kpDataAccount) {
LedgerBlock preBlock = ledgerRepo.getLatestBlock();
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(preBlock);

// 加载合约
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
opReg, ledgerManager);

// 注册数据账户;
TxBuilder txBuilder = new TxBuilder(ledgerHash);

txBuilder.dataAccounts().register(kpDataAccount.getIdentity());
TransactionRequestBuilder txReqBuilder1 = txBuilder.prepareRequest();
txReqBuilder1.signAsEndpoint(parti0);
txReqBuilder1.signAsNode(parti0);
TransactionRequest txReq = txReqBuilder1.buildRequest();

TransactionResponse resp = txbatchProcessor.schedule(txReq);

TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare();
txResultHandle.commit();

assertNotNull(resp.getBlockHash());
assertEquals(TransactionState.SUCCESS, resp.getExecutionState());
assertEquals(preBlock.getHeight() + 1, resp.getBlockHeight());
}

private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager,
DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, BlockchainKeypair contractKey) {
// 创建新区块的交易处理器;
@@ -300,4 +460,10 @@ public class ContractInvokingTest {
new Random().nextBytes(chainCode);
return chainCode;
}

public static interface TxDefinitor {

void buildTx(TxBuilder txBuilder);

}
}

+ 19
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/KeyValueEntry.java View File

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

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.binaryproto.DataField;
import com.jd.blockchain.binaryproto.PrimitiveType;

@DataContract(code = 0x4010)
public interface KeyValueEntry {

@DataField(order = 1, primitiveType = PrimitiveType.TEXT)
String getKey();

@DataField(order = 2, primitiveType = PrimitiveType.TEXT)
String getValue();

@DataField(order = 3, primitiveType = PrimitiveType.INT64)
long getVersion();

}

+ 47
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/KeyValueObject.java View File

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

public class KeyValueObject implements KeyValueEntry {

private String key;

private String value;

private long version;

public KeyValueObject() {
}

public KeyValueObject(String key, String value, long version) {
this.key = key;
this.value = value;
this.version = version;
}

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

@Override
public String getValue() {
return value;
}

@Override
public long getVersion() {
return version;
}

public void setKey(String key) {
this.key = key;
}

public void setValue(String value) {
this.value = value;
}

public void setVersion(long version) {
this.version = version;
}

}

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

@@ -32,6 +32,38 @@ public class MerkleDataSetTest {

private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(),
SMCryptoService.class.getName() };
/**
* 测试存储的增长;
*/
@Test
public void testKeyIndex() {
CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length];
for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) {
supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]);
}
String keyPrefix = "";
CryptoConfig cryptoConfig = new CryptoConfig();
cryptoConfig.setSupportedProviders(supportedProviders);
cryptoConfig.setHashAlgorithm(ClassicAlgorithm.SHA256);
cryptoConfig.setAutoVerifyHash(true);
MemoryKVStorage storage = new MemoryKVStorage();
MerkleDataSet mds = new MerkleDataSet(cryptoConfig, keyPrefix, storage, storage);
mds.setValue("A", "A".getBytes(), -1);
mds.setValue("B", "B".getBytes(), -1);
mds.setValue("C", "C".getBytes(), -1);
mds.commit();
//校验 Key 的正确性;
assertEquals("A", mds.getKeyAtIndex(0));
assertEquals("B", mds.getKeyAtIndex(1));
assertEquals("C", mds.getKeyAtIndex(2));
}

/**
* 测试存储的增长;
@@ -59,6 +91,7 @@ public class MerkleDataSetTest {

mds.commit();
HashDigest root1 = mds.getRootHash();

// 1个KV项的存储KEY的数量= 1 + 1(保存SN) + Merkle节点数量;
// 所以:3 项;


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

@@ -14,6 +14,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.DataVersionConflictException;
import com.jd.blockchain.ledger.EndpointRequest;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInitSetting;
@@ -245,7 +246,7 @@ public class TransactionBatchProcessorTest {
}

@Test
public void testTxRollbackByVersionsConfliction() {
public void testTxRollbackByVersionsConflict() {
final MemoryKVStorage STORAGE = new MemoryKVStorage();

// 初始化账本到指定的存储库;
@@ -337,7 +338,14 @@ public class TransactionBatchProcessorTest {
txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager);

txbatchProcessor.schedule(txreq5);
txbatchProcessor.schedule(txreq6);
// 预期会产生版本冲突异常; DataVersionConflictionException;
DataVersionConflictException versionConflictionException = null;
try {
txbatchProcessor.schedule(txreq6);
} catch (DataVersionConflictException e) {
versionConflictionException = e;
}
assertNotNull(versionConflictionException);

newBlock = newBlockEditor.prepare();
newBlockEditor.commit();


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

@@ -5,14 +5,11 @@ import com.jd.blockchain.contract.ContractEvent;

@Contract
public interface TxTestContract {
@ContractEvent(name = "testReadable")
boolean testReadable();

// @ContractEvent(name = "prepareData")
// String[] prepareData(String address);
//
// @ContractEvent(name = "doVersionConflictedWritting")
// void doVersionConflictedWritting(String key, String value, long version);
@ContractEvent(name = "testRollbackWhileVersionConfliction")
void testRollbackWhileVersionConfliction(String address, String key, String value, long version);

}

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

@@ -33,18 +33,12 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar
String text2 = (String) v2.getValue();
return text1.equals(text2);
}
@Override
public void testRollbackWhileVersionConfliction(String address, String key, String value, long version) {
eventContext.getLedger().dataAccount(address).setText(key, value, version);
}

// @Override
// public String[] prepareData(String address) {
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public void doVersionConflictedWritting(String key, String value, long version) {
// // TODO Auto-generated method stub
//
// }

@Override
public void postConstruct() {
@@ -76,4 +70,5 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar
this.dataAddress = dataAddress;
}


}

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

@@ -183,10 +183,23 @@ public class BytesValueEncoding {
// 接口序列化必须实现DataContract注解
if (!currParamType.isAnnotationPresent(DataContract.class)) {
throw new IllegalStateException(
String.format("Interface[%s] can not be serialize !!!", currParamType.getName()));
String.format("Interface[%s] can not be annotated as a DataContract!!!", currParamType.getName()));
}
return true;
}
if (currParamType.isArray() ) {
Class<?> componentType = currParamType.getComponentType();
if (componentType.isInterface()) {
// 接口序列化必须实现DataContract注解
if (!componentType.isAnnotationPresent(DataContract.class)) {
throw new IllegalStateException(
String.format("Interface[%s] can not be annotated as a DataContract!!!", currParamType.getName()));
}
return true;
}
}
return CLASS_RESOLVER_MAP.containsKey(currParamType);
}



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

@@ -0,0 +1,27 @@
package com.jd.blockchain.ledger;
public class DataVersionConflictException extends BlockRollbackException {
private static final long serialVersionUID = 3583192000738807503L;
private TransactionState state;
public DataVersionConflictException() {
this(TransactionState.DATA_VERSION_CONFLICT, null);
}
public DataVersionConflictException(String message) {
this(TransactionState.DATA_VERSION_CONFLICT, message);
}
private DataVersionConflictException(TransactionState state, String message) {
super(message);
assert TransactionState.SUCCESS != state;
this.state = state;
}
public TransactionState getState() {
return state;
}
}

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

@@ -38,6 +38,11 @@ public enum TransactionState {
* 合约不存在;
*/
CONTRACT_DOES_NOT_EXIST((byte) 0x04),
/**
* 数据写入时版本冲突;
*/
DATA_VERSION_CONFLICT((byte) 0x05),
/**
* 由于在错误的账本上执行交易而被丢弃;


+ 1
- 1
source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java View File

@@ -81,7 +81,7 @@ public abstract class RuntimeContext {
if (jarFile.isFile()) {
FileUtils.deleteFile(jarFile);
} else {
throw new IllegalStateException("Code storage confliction! --" + jarFile.getAbsolutePath());
throw new IllegalStateException("Code storage conflict! --" + jarFile.getAbsolutePath());
}
}
FileUtils.writeBytes(jarBytes, jarFile);


Loading…
Cancel
Save