diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java index 2b5e8b9859..95f436b19f 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -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(); + } } diff --git a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java index 73b9efaa35..2488686bfb 100644 --- a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java @@ -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", diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index cb7164a3ba..9b7bbf6562 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1802,6 +1802,12 @@ private void processBlock(BlockCapsule block, List txs) List 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); diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index a7fc2feaf8..a9cf1087c2 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -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; @@ -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()); } @@ -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)); @@ -754,7 +757,7 @@ public void fork() long num = chainManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(); BlockCapsule blockCapsule0 = createTestBlockCapsule( - 1533529947843L + 3000, + 1533529947000L + 3000, num + 1, chainManager.getDynamicPropertiesStore().getLatestBlockHeaderHash() .getByteString(), @@ -762,7 +765,7 @@ public void fork() BlockCapsule blockCapsule1 = createTestBlockCapsule( - 1533529947843L + 3000, + 1533529947000L + 3000, num + 1, chainManager.getDynamicPropertiesStore().getLatestBlockHeaderHash() .getByteString(), @@ -773,7 +776,7 @@ public void fork() BlockCapsule blockCapsule2 = createTestBlockCapsule( - 1533529947843L + 6000, + 1533529947000L + 6000, num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys); dbManager.pushBlock(blockCapsule2); @@ -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 @@ -1095,6 +1116,36 @@ private BlockCapsule createTestBlockCapsule(long time, return blockCapsule; } + private BlockCapsule createTestBlockCapsule2(long time, long number, ByteString hash, + Map 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 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 addressToProvateKeys) {