Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(validate): strengthen transaction result verification #6221

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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