use of io.nuls.consensus.poc.protocol.entity.RedPunishData in project nuls by nuls-io.
the class DepositTxProcessor method conflictDetect.
/**
* 冲突检测,检测如果传入的交易列表中有相冲突的交易,则返回失败,写明失败原因及所有的应该舍弃的交易列表
* 本方法不检查双花冲突,双花由账本接口实现
* <p>
* Conflict detection, which detects conflicting transactions in the incoming transaction list, returns failure,
* indicating the cause of failure and all the list of trades that should be discarded.
* This method does not check the double flower conflict, the double flower is realized by the accounting interface.
*
* @param txList 需要检查的交易列表/A list of transactions to be checked.
* @return 操作结果:成功则返回successResult,失败时,data中返回丢弃列表,msg中返回冲突原因
* Operation result: success returns successResult. When failure, data returns the discard list, and MSG returns the cause of conflict.
*/
@Override
public ValidateResult conflictDetect(List<Transaction> txList) {
if (null == txList || txList.isEmpty()) {
return ValidateResult.getSuccessResult();
}
Set<NulsDigestData> outAgentHash = new HashSet<>();
Map<NulsDigestData, Na> naMap = new HashMap<>();
List<DepositTransaction> dTxList = new ArrayList<>();
for (Transaction transaction : txList) {
switch(transaction.getType()) {
case ConsensusConstant.TX_TYPE_STOP_AGENT:
StopAgentTransaction stopAgentTransaction = (StopAgentTransaction) transaction;
outAgentHash.add(stopAgentTransaction.getTxData().getCreateTxHash());
break;
case ConsensusConstant.TX_TYPE_JOIN_CONSENSUS:
DepositTransaction depositTransaction = (DepositTransaction) transaction;
Na na = naMap.get(depositTransaction.getTxData().getAgentHash());
if (null == na) {
na = getAgentTotalDeposit(depositTransaction.getTxData().getAgentHash());
}
if (na == null) {
na = depositTransaction.getTxData().getDeposit();
} else {
na = na.add(depositTransaction.getTxData().getDeposit());
}
if (na.isGreaterThan(PocConsensusProtocolConstant.SUM_OF_DEPOSIT_OF_AGENT_UPPER_LIMIT)) {
ValidateResult validateResult = ValidateResult.getFailedResult(this.getClass().getName(), PocConsensusErrorCode.DEPOSIT_TOO_MUCH);
validateResult.setData(transaction);
return validateResult;
} else {
naMap.put(depositTransaction.getTxData().getAgentHash(), na);
}
dTxList.add(depositTransaction);
break;
case ConsensusConstant.TX_TYPE_RED_PUNISH:
RedPunishTransaction redPunishTransaction = (RedPunishTransaction) transaction;
RedPunishData redPunishData = redPunishTransaction.getTxData();
AgentPo agent = this.getAgentByAddress(redPunishData.getAddress());
if (null != agent) {
outAgentHash.add(agent.getHash());
}
break;
default:
continue;
}
}
if (dTxList.isEmpty() || outAgentHash.isEmpty()) {
return ValidateResult.getSuccessResult();
}
for (DepositTransaction depositTransaction : dTxList) {
if (outAgentHash.contains(depositTransaction.getTxData().getAgentHash())) {
ValidateResult validateResult = ValidateResult.getFailedResult(this.getClass().getName(), PocConsensusErrorCode.AGENT_STOPPED);
validateResult.setData(depositTransaction);
return validateResult;
}
}
return ValidateResult.getSuccessResult();
}
use of io.nuls.consensus.poc.protocol.entity.RedPunishData in project nuls by nuls-io.
the class RedPunishTxProcessor method onRollback.
@Override
public Result onRollback(RedPunishTransaction tx, Object secondaryData) {
RedPunishData punishData = tx.getTxData();
List<AgentPo> agentList = agentStorageService.getList();
AgentPo agent = null;
for (AgentPo agentPo : agentList) {
if (agentPo.getDelHeight() <= 0) {
continue;
}
if (Arrays.equals(agentPo.getAgentAddress(), punishData.getAddress())) {
agent = agentPo;
break;
}
}
if (null == agent) {
return Result.getFailed(PocConsensusErrorCode.AGENT_NOT_EXIST);
}
List<DepositPo> depositPoList = depositStorageService.getList();
List<DepositPo> updatedList = new ArrayList<>();
for (DepositPo po : depositPoList) {
po.setDelHeight(-1);
boolean success = this.depositStorageService.save(po);
if (!success) {
for (DepositPo po2 : depositPoList) {
po2.setDelHeight(tx.getBlockHeight());
this.depositStorageService.save(po2);
}
return Result.getFailed(PocConsensusErrorCode.UPDATE_DEPOSIT_FAILED);
}
updatedList.add(po);
}
AgentPo agentPo = agent;
agentPo.setDelHeight(-1L);
boolean success = agentStorageService.save(agentPo);
if (!success) {
for (DepositPo po2 : depositPoList) {
po2.setDelHeight(tx.getBlockHeight());
this.depositStorageService.save(po2);
}
return Result.getFailed(PocConsensusErrorCode.UPDATE_AGENT_FAILED);
}
byte[] key = ArraysTool.concatenate(punishData.getAddress(), new byte[] { PunishType.RED.getCode() }, SerializeUtils.uint64ToByteArray(tx.getBlockHeight()), new byte[] { 0 });
success = storageService.delete(key);
if (!success) {
for (DepositPo po2 : depositPoList) {
po2.setDelHeight(tx.getBlockHeight());
this.depositStorageService.save(po2);
}
agentPo.setDelHeight(tx.getBlockHeight());
agentStorageService.save(agentPo);
throw new NulsRuntimeException(TransactionErrorCode.ROLLBACK_TRANSACTION_FAILED);
}
return Result.getSuccess();
}
use of io.nuls.consensus.poc.protocol.entity.RedPunishData in project nuls by nuls-io.
the class ChainContainer method verifyRedPunish.
private boolean verifyRedPunish(RedPunishTransaction data) {
RedPunishData punishData = data.getTxData();
if (ConsensusConfig.getSeedNodeStringList().contains(AddressTool.getStringAddressByBytes(punishData.getAddress()))) {
Log.warn("The seed node can not be punished!");
return false;
}
HeaderSignValidator validator = NulsContext.getServiceBean(HeaderSignValidator.class);
LedgerService ledgerService = NulsContext.getServiceBean(LedgerService.class);
if (punishData.getReasonCode() == PunishReasonEnum.DOUBLE_SPEND.getCode()) {
if (NulsContext.MAIN_NET_VERSION <= 1) {
Log.warn("The red punish tx need higher version!");
return false;
}
SmallBlock smallBlock = new SmallBlock();
try {
smallBlock.parse(punishData.getEvidence(), 0);
} catch (NulsException e) {
Log.error(e);
return false;
}
BlockHeader header = smallBlock.getHeader();
if (header.getTime() != data.getTime()) {
return false;
}
ValidateResult result = validator.validate(header);
if (result.isFailed()) {
Log.warn(result.getMsg());
return false;
}
List<NulsDigestData> txHashList = smallBlock.getTxHashList();
if (!header.getMerkleHash().equals(NulsDigestData.calcMerkleDigestData(txHashList))) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
List<Transaction> txList = smallBlock.getSubTxList();
if (null == txList || txList.size() < 2) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
result = ledgerService.verifyDoubleSpend(txList);
if (result.isSuccess()) {
Log.warn(PocConsensusErrorCode.TRANSACTIONS_NEVER_DOUBLE_SPEND.getMsg());
return false;
}
} else if (punishData.getReasonCode() == PunishReasonEnum.BIFURCATION.getCode()) {
if (NulsContext.MAIN_NET_VERSION <= 1) {
Log.warn("The red punish tx need higher version!");
return false;
}
NulsByteBuffer byteBuffer = new NulsByteBuffer(punishData.getEvidence());
// 轮次
long[] roundIndex = new long[NulsContext.REDPUNISH_BIFURCATION];
for (int i = 0; i < NulsContext.REDPUNISH_BIFURCATION && !byteBuffer.isFinished(); i++) {
BlockHeader header1 = null;
BlockHeader header2 = null;
try {
header1 = byteBuffer.readNulsData(new BlockHeader());
header2 = byteBuffer.readNulsData(new BlockHeader());
} catch (NulsException e) {
Log.error(e);
}
if (null == header1 || null == header2) {
Log.warn(KernelErrorCode.DATA_NOT_FOUND.getMsg());
return false;
}
if (header1.getHeight() != header2.getHeight()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
if (i == NulsContext.REDPUNISH_BIFURCATION - 1 && (header1.getTime() + header2.getTime()) / 2 != data.getTime()) {
return false;
}
ValidateResult result = validator.validate(header1);
if (result.isFailed()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
result = validator.validate(header2);
if (result.isFailed()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
if (!Arrays.equals(header1.getBlockSignature().getPublicKey(), header2.getBlockSignature().getPublicKey())) {
Log.warn(TransactionErrorCode.SIGNATURE_ERROR.getMsg());
return false;
}
BlockExtendsData blockExtendsData = new BlockExtendsData(header1.getExtend());
roundIndex[i] = blockExtendsData.getRoundIndex();
}
// 验证轮次是否连续
boolean rs = true;
for (int i = 0; i < roundIndex.length; i++) {
if (i < roundIndex.length - 2 && roundIndex[i + 1] - roundIndex[i] != 1) {
rs = false;
break;
}
}
if (!rs) {
Log.warn(PocConsensusErrorCode.RED_CARD_VERIFICATION_FAILED.getMsg());
return false;
}
} else if (punishData.getReasonCode() != PunishReasonEnum.TOO_MUCH_YELLOW_PUNISH.getCode()) {
Log.warn(PocConsensusErrorCode.RED_CARD_VERIFICATION_FAILED.getMsg());
return false;
}
try {
return verifyCoinData(data);
} catch (IOException e) {
Log.error(e);
return false;
}
}
use of io.nuls.consensus.poc.protocol.entity.RedPunishData in project nuls by nuls-io.
the class ChainContainer method verifyPunishTx.
// Verify penalties
// 验证处罚交易
public boolean verifyPunishTx(Block block, MeetingRound currentRound, MeetingMember member) {
List<Transaction> txs = block.getTxs();
Transaction tx = txs.get(0);
if (tx.getType() != ProtocolConstant.TX_TYPE_COINBASE) {
BlockLog.debug("Coinbase transaction order wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
// Log.error("Coinbase transaction order wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
return false;
}
List<RedPunishTransaction> redPunishTxList = new ArrayList<>();
YellowPunishTransaction yellowPunishTx = null;
for (int i = 1; i < txs.size(); i++) {
Transaction transaction = txs.get(i);
if (transaction.getType() == ProtocolConstant.TX_TYPE_COINBASE) {
BlockLog.debug("Coinbase transaction more than one! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
// Log.error("Coinbase transaction more than one! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
return false;
}
if (null == yellowPunishTx && transaction.getType() == ConsensusConstant.TX_TYPE_YELLOW_PUNISH) {
yellowPunishTx = (YellowPunishTransaction) transaction;
} else if (null != yellowPunishTx && transaction.getType() == ConsensusConstant.TX_TYPE_YELLOW_PUNISH) {
BlockLog.debug("Yellow punish transaction more than one! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
// Log.error("Yellow punish transaction more than one! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
return false;
} else if (transaction.getType() == ConsensusConstant.TX_TYPE_RED_PUNISH) {
redPunishTxList.add((RedPunishTransaction) transaction);
}
}
YellowPunishTransaction yellowPunishTransaction = null;
try {
yellowPunishTransaction = ConsensusTool.createYellowPunishTx(chain.getBestBlock(), member, currentRound);
if (yellowPunishTransaction == null && yellowPunishTx == null) {
// 继续
} else if (yellowPunishTransaction == null || yellowPunishTx == null) {
BlockLog.debug("The yellow punish tx is wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
// Log.error("The yellow punish tx is wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
return false;
} else if (!yellowPunishTransaction.getHash().equals(yellowPunishTx.getHash())) {
BlockLog.debug("The yellow punish tx's hash is wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
// Log.error("The yellow punish tx's hash is wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
return false;
}
} catch (Exception e) {
BlockLog.debug("The tx's wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash(), e);
// Log.error("The tx's wrong! height: " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash(), e);
return false;
}
if (!redPunishTxList.isEmpty()) {
Set<String> punishAddress = new HashSet<>();
if (null != yellowPunishTx) {
List<byte[]> addressList = yellowPunishTx.getTxData().getAddressList();
for (byte[] address : addressList) {
MeetingMember item = currentRound.getMemberByAgentAddress(address);
if (null == item) {
item = currentRound.getPreRound().getMemberByAgentAddress(address);
}
if (item.getCreditVal() <= PocConsensusConstant.RED_PUNISH_CREDIT_VAL) {
punishAddress.add(AddressTool.getStringAddressByBytes(item.getAgent().getAgentAddress()));
}
}
}
int countOfTooMuchYP = 0;
Set<String> redPunishAddressSet = new HashSet<>();
for (RedPunishTransaction redTx : redPunishTxList) {
RedPunishData data = redTx.getTxData();
if (data.getReasonCode() == PunishReasonEnum.TOO_MUCH_YELLOW_PUNISH.getCode()) {
countOfTooMuchYP++;
if (!punishAddress.contains(AddressTool.getStringAddressByBytes(redTx.getTxData().getAddress()))) {
BlockLog.debug("There is a wrong red punish tx!" + block.getHeader().getHash());
return false;
}
if (NulsContext.MAIN_NET_VERSION > 1 && redTx.getTime() != block.getHeader().getTime()) {
BlockLog.debug("red punish CoinData & TX time is wrong! " + block.getHeader().getHash());
return false;
}
}
boolean result = verifyRedPunish(redTx);
if (!result) {
return result;
}
if (!redPunishAddressSet.add(AddressTool.getStringAddressByBytes(redTx.getTxData().getAddress()))) {
BlockLog.debug("red punish repeat!" + block.getHeader().getHash());
return false;
}
}
if (countOfTooMuchYP != punishAddress.size()) {
BlockLog.debug("There is a wrong red punish tx!" + block.getHeader().getHash());
return false;
}
}
return true;
}
use of io.nuls.consensus.poc.protocol.entity.RedPunishData in project nuls by nuls-io.
the class RedPunishTxProcessor method onCommit.
@Override
public Result onCommit(RedPunishTransaction tx, Object secondaryData) {
RedPunishData punishData = tx.getTxData();
BlockHeader header = (BlockHeader) secondaryData;
BlockExtendsData roundData = new BlockExtendsData(header.getExtend());
PunishLogPo punishLogPo = new PunishLogPo();
punishLogPo.setAddress(punishData.getAddress());
punishLogPo.setHeight(tx.getBlockHeight());
punishLogPo.setRoundIndex(roundData.getRoundIndex());
punishLogPo.setTime(tx.getTime());
punishLogPo.setType(PunishType.RED.getCode());
punishLogPo.setEvidence(punishData.getEvidence());
punishLogPo.setReasonCode(punishData.getReasonCode());
List<AgentPo> agentList = agentStorageService.getList();
AgentPo agent = null;
for (AgentPo agentPo : agentList) {
if (agentPo.getDelHeight() > 0) {
continue;
}
if (Arrays.equals(agentPo.getAgentAddress(), punishLogPo.getAddress())) {
agent = agentPo;
break;
}
}
if (null == agent) {
Log.error("There is no agent can be punished.");
return Result.getSuccess();
}
List<DepositPo> depositPoList = depositStorageService.getList();
List<DepositPo> updatedList = new ArrayList<>();
for (DepositPo po : depositPoList) {
if (po.getDelHeight() >= 0) {
continue;
}
if (!po.getAgentHash().equals(agent.getHash())) {
continue;
}
po.setDelHeight(tx.getBlockHeight());
boolean b = depositStorageService.save(po);
if (!b) {
for (DepositPo po2 : updatedList) {
po2.setDelHeight(-1);
this.depositStorageService.save(po2);
}
return ValidateResult.getFailedResult(this.getClass().getName(), PocConsensusErrorCode.UPDATE_DEPOSIT_FAILED);
}
updatedList.add(po);
}
boolean success = storageService.save(punishLogPo);
if (!success) {
for (DepositPo po2 : updatedList) {
po2.setDelHeight(-1);
this.depositStorageService.save(po2);
}
throw new NulsRuntimeException(TransactionErrorCode.ROLLBACK_TRANSACTION_FAILED);
}
AgentPo agentPo = agent;
agentPo.setDelHeight(tx.getBlockHeight());
success = agentStorageService.save(agentPo);
if (!success) {
for (DepositPo po2 : updatedList) {
po2.setDelHeight(-1);
this.depositStorageService.save(po2);
}
this.storageService.delete(punishLogPo.getKey());
return Result.getFailed(PocConsensusErrorCode.UPDATE_AGENT_FAILED);
}
return Result.getSuccess();
}
Aggregations