Browse Source

Fixed the bug that did not correctly handle transaction state when the writing DataAccount did not exist;

tags/1.0.1
huanghaiquan 5 years ago
parent
commit
c72b3397ad
12 changed files with 151 additions and 113 deletions
  1. +13
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java
  2. +7
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
  3. +14
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
  4. +4
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java
  5. +10
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
  6. +36
    -18
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
  7. +16
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractDoesNotExistException.java
  8. +16
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountDoesNotExistException.java
  9. +2
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerException.java
  10. +16
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
  11. +15
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserDoesNotExistException.java
  12. +2
    -83
      source/storage/storage-service/src/test/java/test/com/jd/blockchain/storage/service/utils/BufferedKVStorageTest.java

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

@@ -14,9 +14,9 @@ public class DataAccountSet implements MerkleProvable, Transactional {
private AccountSet accountSet;
public DataAccountSet(CryptoSetting cryptoSetting, String prefix,ExPolicyKVStorage exStorage,
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage,
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) {
accountSet = new AccountSet(cryptoSetting,prefix, exStorage, verStorage, accessPolicy);
accountSet = new AccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy);
}
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix,
@@ -26,7 +26,7 @@ public class DataAccountSet implements MerkleProvable, Transactional {
}
public AccountHeader[] getAccounts(int fromIndex, int count) {
return accountSet.getAccounts(fromIndex,count);
return accountSet.getAccounts(fromIndex, count);
}
public boolean isReadonly() {
@@ -56,8 +56,18 @@ public class DataAccountSet implements MerkleProvable, Transactional {
return new DataAccount(accBase);
}
/**
* 返回数据账户; <br>
* 如果不存在,则返回 null;
*
* @param address
* @return
*/
public DataAccount getDataAccount(Bytes address) {
BaseAccount accBase = accountSet.getAccount(address);
if (accBase == null) {
return null;
}
return new DataAccount(accBase);
}


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

@@ -123,6 +123,12 @@ public class LedgerTransactionalEditor implements LedgerEditor {
return ledgerHash;
}

/**
* 检查当前账本是否是指定交易请求的账本;
*
* @param txRequest
* @return
*/
private boolean isRequestedLedger(TransactionRequest txRequest) {
HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash();
if (ledgerHash == reqLedgerHash) {
@@ -142,8 +148,8 @@ public class LedgerTransactionalEditor implements LedgerEditor {
+ txRequest.getTransactionContent().getHash() + "]!");
}

// 检查状态是否允许创建新的交易请求;;
checkState();
// TODO:验证交易签名;

BufferedKVStorage txBuffStorage = null;
LedgerDataSetImpl txDataset = null;


+ 14
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java View File

@@ -9,6 +9,8 @@ import org.slf4j.LoggerFactory;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.ContractDoesNotExistException;
import com.jd.blockchain.ledger.DataAccountDoesNotExistException;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException;
@@ -19,6 +21,7 @@ import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.UserDoesNotExistException;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerEditor;
import com.jd.blockchain.ledger.core.LedgerService;
@@ -111,10 +114,10 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {

// 处理交易;
resp = handleTx(request, txCtx);
LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]",
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash());
responseList.add(resp);
return resp;
} catch (Exception e) {
@@ -124,7 +127,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
"Discard transaction rollback caused by the system exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s",
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),
e.getMessage()), e);
responseList.add(resp);
return resp;
}
@@ -186,7 +189,14 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
} catch (LedgerException e) {
// TODO: 识别更详细的异常类型以及执行对应的处理;
result = TransactionState.LEDGER_ERROR;
txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults);
if (e instanceof DataAccountDoesNotExistException) {
result = TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST;
} else if (e instanceof UserDoesNotExistException) {
result = TransactionState.USER_DOES_NOT_EXIST;
} else if (e instanceof ContractDoesNotExistException) {
result = TransactionState.CONTRACT_DOES_NOT_EXIST;
}
txCtx.discardAndCommit(result, operationResults);
LOGGER.error(String.format(
"Transaction rollback caused by the ledger exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s",
newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(),


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

@@ -4,6 +4,7 @@ import org.springframework.stereotype.Service;

import com.jd.blockchain.binaryproto.DataContractRegistry;
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.Operation;
@@ -26,9 +27,11 @@ public class DataAccountKVSetOperationHandle implements OperationHandle {
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) {
DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op;
DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress());
if (account == null) {
throw new DataAccountDoesNotExistException("DataAccount doesn't exist!");
}
KVWriteEntry[] writeSet = kvWriteOp.getWriteSet();
for (KVWriteEntry kvw : writeSet) {
// byte[] value = BinaryProtocol.encode(kvw.getValue(), BytesValue.class);
account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion());
}
return null;


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

@@ -125,12 +125,20 @@ public class LedgerTestUtils {
return txReqBuilder.buildRequest();
}

public static TransactionRequest createTxRequest_MultiOPs_WithError(BlockchainKeypair userKeypair, HashDigest ledgerHash,
BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) {
/**
* @param userKeypair 要注册的用户key;
* @param ledgerHash 账本哈希;
* @param nodeKeypair 节点key;
* @param signers 签名者列表;
* @return
*/
public static TransactionRequest createTxRequest_MultiOPs_WithNotExistedDataAccount(BlockchainKeypair userKeypair,
HashDigest ledgerHash, BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) {
TxBuilder txBuilder = new TxBuilder(ledgerHash);

txBuilder.users().register(userKeypair.getIdentity());

// 故意构建一个错误的
BlockchainKeypair testKey = BlockchainKeyGenerator.getInstance().generate();
txBuilder.dataAccount(testKey.getAddress()).setBytes("AA", "Value".getBytes(), 1);



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

@@ -57,8 +57,6 @@ public class TransactionBatchProcessorTest {

private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 };

private TransactionRequest transactionRequest;

// TODO: 验证无效签名会被拒绝;

@Test
@@ -88,7 +86,8 @@ public class TransactionBatchProcessorTest {

// 注册新用户;
BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair, ledgerHash, parti0, parti0);
TransactionRequest transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair, ledgerHash, parti0,
parti0);
TransactionResponse txResp = txbatchProcessor.schedule(transactionRequest);

LedgerBlock newBlock = newBlockEditor.prepare();
@@ -132,18 +131,20 @@ public class TransactionBatchProcessorTest {

// 注册新用户;
BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, parti0, parti0);
TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest);
TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash,
parti0, parti0);
TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest1);

// BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate();
// transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair2, parti0);
// TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest);
BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate();
TransactionRequest transactionRequest2 = LedgerTestUtils.createTxRequest_UserReg(userKeypair2, ledgerHash,
parti0, parti0);
TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest2);

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

assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState());
// assertEquals(TransactionState.SUCCESS, txResp2.getExecutionState());
assertEquals(TransactionState.SUCCESS, txResp2.getExecutionState());

// 验证正确性;
ledgerManager = new LedgerManager();
@@ -155,9 +156,9 @@ public class TransactionBatchProcessorTest {

LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock);
boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress());
// boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress());
boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress());
assertTrue(existUser1);
// assertTrue(existUser2);
assertTrue(existUser2);
}

@Test
@@ -187,22 +188,25 @@ public class TransactionBatchProcessorTest {

// 注册新用户;
BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, parti0, parti0);
TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest);
TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash,
parti0, parti0);
TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest1);

BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_MultiOPs_WithError(userKeypair2, ledgerHash, parti0, parti0);
TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest);
TransactionRequest transactionRequest2 = LedgerTestUtils
.createTxRequest_MultiOPs_WithNotExistedDataAccount(userKeypair2, ledgerHash, parti0, parti0);
TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest2);

BlockchainKeypair userKeypair3 = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair3, ledgerHash, parti0, parti0);
TransactionResponse txResp3 = txbatchProcessor.schedule(transactionRequest);
TransactionRequest transactionRequest3 = LedgerTestUtils.createTxRequest_UserReg(userKeypair3, ledgerHash,
parti0, parti0);
TransactionResponse txResp3 = txbatchProcessor.schedule(transactionRequest3);

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

assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState());
assertEquals(TransactionState.LEDGER_ERROR, txResp2.getExecutionState());
assertEquals(TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST, txResp2.getExecutionState());
assertEquals(TransactionState.SUCCESS, txResp3.getExecutionState());

// 验证正确性;
@@ -213,6 +217,20 @@ public class TransactionBatchProcessorTest {
assertEquals(newBlock.getHash(), latestBlock.getHash());
assertEquals(1, newBlock.getHeight());

LedgerTransaction tx1 = ledgerRepo.getTransactionSet()
.get(transactionRequest1.getTransactionContent().getHash());
LedgerTransaction tx2 = ledgerRepo.getTransactionSet()
.get(transactionRequest2.getTransactionContent().getHash());
LedgerTransaction tx3 = ledgerRepo.getTransactionSet()
.get(transactionRequest3.getTransactionContent().getHash());
assertNotNull(tx1);
assertEquals(TransactionState.SUCCESS, tx1.getExecutionState());
assertNotNull(tx2);
assertEquals(TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST, tx2.getExecutionState());
assertNotNull(tx3);
assertEquals(TransactionState.SUCCESS, tx3.getExecutionState());

LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock);
boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress());
boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress());


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

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

public class ContractDoesNotExistException extends LedgerException {


private static final long serialVersionUID = 8685914012112243771L;

public ContractDoesNotExistException(String message) {
super(message);
}

public ContractDoesNotExistException(String message, Throwable cause) {
super(message, cause);
}

}

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

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

public class DataAccountDoesNotExistException extends LedgerException {

private static final long serialVersionUID = -1889587937401974215L;

public DataAccountDoesNotExistException(String message) {
super(message);
}

public DataAccountDoesNotExistException(String message, Throwable cause) {
super(message, cause);
}

}

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

@@ -3,6 +3,8 @@ package com.jd.blockchain.ledger;
public class LedgerException extends RuntimeException {

private static final long serialVersionUID = -4090881296855827888L;

public LedgerException(String message) {
super(message);


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

@@ -33,12 +33,27 @@ public enum TransactionState {
* 由于在错误的账本上执行交易而被丢弃;
*/
DISCARD_BY_WRONG_LEDGER((byte) 3),
/**
* 由于交易内容的验签失败而丢弃;
*/
DISCARD_BY_WRONG_CONTENT_SIGNATURE((byte) 4),
/**
* 数据账户不存在;
*/
DATA_ACCOUNT_DOES_NOT_EXIST((byte) 5),
/**
* 用户不存在;
*/
USER_DOES_NOT_EXIST((byte) 6),
/**
* 合约不存在;
*/
CONTRACT_DOES_NOT_EXIST((byte) 6),
/**
* 系统错误;
*/


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

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

public class UserDoesNotExistException extends LedgerException {

private static final long serialVersionUID = 397450363050148898L;

public UserDoesNotExistException(String message) {
super(message);
}

public UserDoesNotExistException(String message, Throwable cause) {
super(message, cause);
}

}

+ 2
- 83
source/storage/storage-service/src/test/java/test/com/jd/blockchain/storage/service/utils/BufferedKVStorageTest.java View File

@@ -1,9 +1,9 @@
package test.com.jd.blockchain.storage.service.utils;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -15,14 +15,11 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.verification.VerificationMode;

import com.jd.blockchain.storage.service.ExPolicyKVStorage;
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy;
import com.jd.blockchain.storage.service.VersioningKVStorage;
import com.jd.blockchain.storage.service.utils.BufferedKVStorage;
import com.jd.blockchain.storage.service.utils.ExistancePolicyKVStorageMap;
import com.jd.blockchain.storage.service.utils.VersioningKVStorageMap;
import com.jd.blockchain.utils.Bytes;

public class BufferedKVStorageTest {
@@ -77,82 +74,4 @@ public class BufferedKVStorageTest {
verify(exStorage, times(1)).set(eq(Bytes.fromString("C")), any(), eq(ExPolicy.NOT_EXISTING));
verify(exStorage, times(1)).set(eq(Bytes.fromString("D")), any(), eq(ExPolicy.NOT_EXISTING));
}

// 改变了存储结构,此测试用例不再适合;
// @Test
// public void testDataSet() {
//
// ExistancePolicyKVStorageMap memoryExStorage = new
// ExistancePolicyKVStorageMap();
//
// VersioningKVStorageMap memoryVerStorage = new VersioningKVStorageMap();
//
// long v = memoryVerStorage.set("A", "A1".getBytes(), -1);
// assertEquals(0, v);
// v = memoryVerStorage.set("A", "A2".getBytes(), 0);
// assertEquals(1, v);
// v = memoryVerStorage.set("A", "A3".getBytes(), 1);
// assertEquals(2, v);
// v = memoryVerStorage.set("B", "B1".getBytes(), -1);
// assertEquals(0, v);
//
// BufferedKVStorage bufferedStorage = new BufferedKVStorage(memoryExStorage,
// memoryVerStorage, false);
//
// // test versioning get;
// byte[] value = bufferedStorage.get("A", 0);
// assertEquals("A1", new String(value));
//
// value = bufferedStorage.get("A", -1);
// assertEquals("A3", new String(value));
//
// value = bufferedStorage.get("A", 2);
// assertEquals("A3", new String(value));
//
// value = bufferedStorage.get("B", 0);
// assertEquals("B1", new String(value));
//
//
// // test versioning buffered set;
// v = bufferedStorage.set("C", "C1".getBytes(), -1);
// assertEquals(v, 0);
//
// v = bufferedStorage.set("C", "C2".getBytes(), 0);
// assertEquals(v, 1);
//
// v = bufferedStorage.set("D", "D1".getBytes(), -1);
// assertEquals(v, 0);
//
// v = bufferedStorage.set("E", "E1".getBytes(), 0);
// assertEquals(v, -1);
//
//
// value = bufferedStorage.get("C", 0);
// assertEquals("C1", new String(value));
// value = bufferedStorage.get("C", 1);
// assertEquals("C2", new String(value));
// value = bufferedStorage.get("D", 0);
// assertEquals("D1", new String(value));
// value = bufferedStorage.get("E", 0);
// assertNull(value);
//
// value = memoryVerStorage.get("C", 0);
// assertNull(value);
// value = memoryVerStorage.get("D", 0);
// assertNull(value);
// value = memoryVerStorage.get("E", 0);
// assertNull(value);
//
// bufferedStorage.flush();
//
// value = memoryVerStorage.get("C", 0);
// assertEquals("C1", new String(value));
// value = memoryVerStorage.get("C", 1);
// assertEquals("C2", new String(value));
// value = memoryVerStorage.get("D", 0);
// assertEquals("D1", new String(value));
// value = memoryVerStorage.get("E", 0);
// assertNull(value);
// }

}

Loading…
Cancel
Save