Skip to content

Commit

Permalink
Merge pull request #6221 from lxcmyf/feature/consensus_optimize_tx
Browse files Browse the repository at this point in the history
feat(validate): strengthen transaction result verification
  • Loading branch information
CodeNinjaEvan authored Feb 27, 2025
2 parents 7a15f50 + af3a002 commit 93dfc33
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -878,4 +878,17 @@ public void checkExpiration(long nextSlotTime) throws TransactionExpirationExcep
getExpiration(), nextSlotTime));
}
}

public boolean retCountIsGreatThanContractCount() {
int contractCount = getContractCount();
return getRetCount() > contractCount && contractCount > 0;
}

public int getRetCount() {
return this.getInstance().getRetCount();
}

public int getContractCount() {
return this.getInstance().getRawData().getContractCount();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void consume(TransactionCapsule trx, TransactionTrace trace)
long resultSizeWithMaxContractRet = trx.getResultSizeWithMaxContractRet();
boolean optimizeTxs = !trx.isInBlock() || chainBaseManager
.getDynamicPropertiesStore().allowConsensusLogicOptimization();
if (optimizeTxs && resultSizeWithMaxContractRet >
if (!trx.isInBlock() && resultSizeWithMaxContractRet >
Constant.MAX_RESULT_SIZE_IN_TX * contracts.size()) {
throw new TooBigTransactionResultException(String.format(
"Too big transaction result, TxId %s, the result size is %d bytes, maxResultSize %d",
Expand Down
6 changes: 6 additions & 0 deletions framework/src/main/java/org/tron/core/db/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,12 @@ private void processBlock(BlockCapsule block, List<TransactionCapsule> txs)
List<TransactionInfo> results = new ArrayList<>();
long num = block.getNum();
for (TransactionCapsule transactionCapsule : block.getTransactions()) {
if (chainBaseManager.getDynamicPropertiesStore().allowConsensusLogicOptimization()
&& transactionCapsule.retCountIsGreatThanContractCount()) {
throw new BadBlockException(String.format("The result count %d of this transaction %s is "
+ "greater than its contract count %d", transactionCapsule.getRetCount(),
transactionCapsule.getTransactionId(), transactionCapsule.getContractCount()));
}
transactionCapsule.setBlockNum(num);
if (block.generatedByMyself) {
transactionCapsule.setVerified(true);
Expand Down
61 changes: 56 additions & 5 deletions framework/src/test/java/org/tron/core/db/ManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
import static org.tron.common.utils.Commons.adjustAssetBalanceV2;
import static org.tron.common.utils.Commons.adjustTotalShieldedPoolValue;
import static org.tron.common.utils.Commons.getExchangeStoreFinal;
import static org.tron.common.utils.StringUtil.encode58Check;
import static org.tron.core.exception.BadBlockException.TypeEnum.CALC_MERKLE_ROOT_FAILED;
import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS;

import com.beust.jcommander.internal.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.protobuf.Any;
Expand Down Expand Up @@ -481,7 +484,7 @@ public void adjustAssetBalanceV2Test() {
} catch (BalanceInsufficientException e) {
Assert.assertTrue(e instanceof BalanceInsufficientException);
Assert.assertEquals(
"reduceAssetAmount failed! account: " + StringUtil.encode58Check(account.createDbKey()),
"reduceAssetAmount failed! account: " + encode58Check(account.createDbKey()),
e.getMessage());
}

Expand Down Expand Up @@ -744,7 +747,7 @@ public void fork()
chainManager.addWitness(ByteString.copyFrom(address));
chainManager.getWitnessStore().put(address, witnessCapsule);

Block block = getSignedBlock(witnessCapsule.getAddress(), 1533529947843L, privateKey);
Block block = getSignedBlock(witnessCapsule.getAddress(), 1533529947000L, privateKey);

dbManager.pushBlock(new BlockCapsule(block));

Expand All @@ -754,15 +757,15 @@ public void fork()
long num = chainManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber();
BlockCapsule blockCapsule0 =
createTestBlockCapsule(
1533529947843L + 3000,
1533529947000L + 3000,
num + 1,
chainManager.getDynamicPropertiesStore().getLatestBlockHeaderHash()
.getByteString(),
addressToProvateKeys);

BlockCapsule blockCapsule1 =
createTestBlockCapsule(
1533529947843L + 3000,
1533529947000L + 3000,
num + 1,
chainManager.getDynamicPropertiesStore().getLatestBlockHeaderHash()
.getByteString(),
Expand All @@ -773,7 +776,7 @@ public void fork()

BlockCapsule blockCapsule2 =
createTestBlockCapsule(
1533529947843L + 6000,
1533529947000L + 6000,
num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);

dbManager.pushBlock(blockCapsule2);
Expand All @@ -800,6 +803,24 @@ public void fork()
Assert.assertEquals(
chainManager.getHead().getBlockId(),
chainManager.getDynamicPropertiesStore().getLatestBlockHeaderHash());

dbManager.getDynamicPropertiesStore().saveConsensusLogicOptimization(1);
BlockCapsule blockCapsule3 =
createTestBlockCapsule2(1533529947000L + 9000,
num + 3, blockCapsule2.getBlockId().getByteString(), addressToProvateKeys);

assertThrows(BadBlockException.class, () -> dbManager.pushBlock(blockCapsule3));
}

private Transaction buildTransaction(com.google.protobuf.Message message,
ContractType contractType) {
Transaction.raw.Builder rawBuilder = Transaction.raw.newBuilder().addContract(
Transaction.Contract.newBuilder().setType(contractType).setParameter(
(message instanceof Any ? (Any) message : Any.pack(message))).build());
Transaction.Builder transactionBuilder = Transaction.newBuilder().setRawData(rawBuilder)
.addRet(Transaction.Result.newBuilder().setContractRet(SUCCESS).build())
.addRet(Transaction.Result.newBuilder().setContractRet(SUCCESS).build());
return transactionBuilder.build();
}

@Test
Expand Down Expand Up @@ -1095,6 +1116,36 @@ private BlockCapsule createTestBlockCapsule(long time,
return blockCapsule;
}

private BlockCapsule createTestBlockCapsule2(long time, long number, ByteString hash,
Map<ByteString, String> addressToProvateKeys) {
TransferContract c1 = TransferContract.newBuilder()
.setOwnerAddress(ByteString.copyFrom("f1".getBytes()))
.setAmount(1).build();
ByteString witnessAddress = dposSlot.getScheduledWitness(dposSlot.getSlot(time));
Protocol.BlockHeader.raw.Builder blockHeaderRawBuild = Protocol.BlockHeader.raw.newBuilder();
Protocol.BlockHeader.raw blockHeaderRaw = blockHeaderRawBuild
.setTimestamp(time)
.setParentHash(hash)
.setWitnessAddress(witnessAddress)
.setNumber(number)
.build();

// block header
Protocol.BlockHeader.Builder blockHeaderBuild = Protocol.BlockHeader.newBuilder();
Protocol.BlockHeader blockHeader = blockHeaderBuild.setRawData(blockHeaderRaw).build();

// block
Block.Builder blockBuild = Block.newBuilder();
List<Transaction> transactions = Lists.newArrayList(buildTransaction(c1,
ContractType.TransferContract));
transactions.forEach(blockBuild::addTransactions);
BlockCapsule blockCapsule = new BlockCapsule(blockBuild.setBlockHeader(blockHeader).build());
blockCapsule.generatedByMyself = true;
blockCapsule.setMerkleRoot();
blockCapsule.sign(ByteArray.fromHexString(addressToProvateKeys.get(witnessAddress)));
return blockCapsule;
}

private BlockCapsule createTestBlockCapsuleError(long time,
long number, ByteString hash,
Map<ByteString, String> addressToProvateKeys) {
Expand Down

0 comments on commit 93dfc33

Please sign in to comment.