Skip to content

feat(*): remove redundant ret for transaction #5839

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

Merged
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 @@ -17,6 +17,7 @@

import static org.tron.common.utils.StringUtil.encode58Check;
import static org.tron.common.utils.WalletUtil.checkPermissionOperations;
import static org.tron.core.Constant.MAX_CONTRACT_RESULT_SIZE;
import static org.tron.core.exception.P2pException.TypeEnum.PROTOBUF_ERROR;

import com.google.common.primitives.Bytes;
Expand Down Expand Up @@ -733,6 +734,15 @@ public long getResultSerializedSize() {
return size;
}

public long getResultSizeWithMaxContractRet() {
long size = 0;
for (Result result : this.transaction.getRetList()) {
size += result.toBuilder().clearContractRet().build().getSerializedSize()
+ MAX_CONTRACT_RESULT_SIZE;
}
return size;
}

@Override
public Transaction getInstance() {
return this.transaction;
Expand Down Expand Up @@ -845,4 +855,18 @@ public BalanceContract.TransferContract getTransferContract() {
return null;
}
}

public void removeRedundantRet() {
Transaction tx = this.getInstance();
List<Result> tmpList = new ArrayList<>(tx.getRetList());
int contractCount = tx.getRawData().getContractCount();
if (tx.getRetCount() > contractCount && contractCount > 0) {
Transaction.Builder transactionBuilder = tx.toBuilder().clearRet();
for (int i = 0; i < contractCount; i++) {
Result result = tmpList.get(i);
transactionBuilder.addRet(result);
}
this.transaction = transactionBuilder.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ public void consume(TransactionCapsule trx, TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException,
TooBigTransactionResultException, TooBigTransactionException {
List<Contract> contracts = trx.getInstance().getRawData().getContractList();
long resultSizeWithMaxContractRet = trx.getResultSizeWithMaxContractRet();
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",
trx.getTransactionId(), resultSizeWithMaxContractRet, Constant.MAX_RESULT_SIZE_IN_TX));
}
if (trx.getResultSerializedSize() > Constant.MAX_RESULT_SIZE_IN_TX * contracts.size()) {
throw new TooBigTransactionResultException();
}
Expand Down
1 change: 1 addition & 0 deletions common/src/main/java/org/tron/core/Constant.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class Constant {
public static final long ENERGY_LIMIT_IN_CONSTANT_TX = 3_000_000L; // ref: 1 us = 1 energy
public static final long MAX_RESULT_SIZE_IN_TX = 64; // max 8 * 8 items in result
public static final long PER_SIGN_LENGTH = 65L;
public static final long MAX_CONTRACT_RESULT_SIZE = 2L;
public static final long PB_DEFAULT_ENERGY_LIMIT = 0L;
public static final long CREATOR_DEFAULT_ENERGY_LIMIT = 1000 * 10_000L;

Expand Down
6 changes: 2 additions & 4 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,6 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) {
trx.setTime(System.currentTimeMillis());
Sha256Hash txID = trx.getTransactionId();
try {
TransactionMessage message = new TransactionMessage(signedTransaction.toByteArray());

if (tronNetDelegate.isBlockUnsolidified()) {
logger.warn("Broadcast transaction {} has failed, block unsolidified.", txID);
return builder.setResult(false).setCode(response_code.BLOCK_UNSOLIDIFIED)
Expand Down Expand Up @@ -550,6 +548,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) {
if (trx.getInstance().getRawData().getContractCount() == 0) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}
TransactionMessage message = new TransactionMessage(trx.getInstance().toByteArray());
dbManager.pushTransaction(trx);
int num = tronNetService.fastBroadcastTransaction(message);
if (num == 0 && minEffectiveConnection != 0) {
Expand Down Expand Up @@ -592,8 +591,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) {
} catch (TooBigTransactionException e) {
logger.warn(BROADCAST_TRANS_FAILED, txID, e.getMessage());
return builder.setResult(false).setCode(response_code.TOO_BIG_TRANSACTION_ERROR)
.setMessage(ByteString.copyFromUtf8("Transaction size is too big."))
.build();
.setMessage(ByteString.copyFromUtf8(e.getMessage())).build();
} catch (TransactionExpirationException e) {
logger.warn(BROADCAST_TRANS_FAILED, txID, e.getMessage());
return builder.setResult(false).setCode(response_code.TRANSACTION_EXPIRATION_ERROR)
Expand Down
17 changes: 8 additions & 9 deletions framework/src/main/java/org/tron/core/db/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ void validateTapos(TransactionCapsule transactionCapsule) throws TaposException
void validateCommon(TransactionCapsule transactionCapsule)
throws TransactionExpirationException, TooBigTransactionException {
if (!transactionCapsule.isInBlock()) {
transactionCapsule.removeRedundantRet();
long generalBytesSize =
transactionCapsule.getInstance().toBuilder().clearRet().build().getSerializedSize()
+ Constant.MAX_RESULT_SIZE_IN_TX + Constant.MAX_RESULT_SIZE_IN_TX;
Expand All @@ -804,7 +805,6 @@ void validateCommon(TransactionCapsule transactionCapsule)
transactionCapsule.getTransactionId(), generalBytesSize, TRANSACTION_MAX_BYTE_SIZE));
}
}

if (transactionCapsule.getData().length > Constant.TRANSACTION_MAX_BYTE_SIZE) {
throw new TooBigTransactionException(String.format(
"Too big transaction, TxId %s, the size is %d bytes, maxTxSize %d",
Expand Down Expand Up @@ -1425,8 +1425,14 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block
if (trxCap == null) {
return null;
}
Contract contract = trxCap.getInstance().getRawData().getContract(0);
Sha256Hash txId = trxCap.getTransactionId();
if (trxCap.getInstance().getRawData().getContractList().size() != 1) {
throw new ContractSizeNotEqualToOneException(
String.format(
"tx %s contract size should be exactly 1, this is extend feature ,actual :%d",
txId, trxCap.getInstance().getRawData().getContractList().size()));
}
Contract contract = trxCap.getInstance().getRawData().getContract(0);
final Histogram.Timer requestTimer = Metrics.histogramStartTimer(
MetricKeys.Histogram.PROCESS_TRANSACTION_LATENCY,
Objects.nonNull(blockCap) ? MetricLabels.BLOCK : MetricLabels.TRX,
Expand All @@ -1442,13 +1448,6 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block
validateTapos(trxCap);
validateCommon(trxCap);

if (trxCap.getInstance().getRawData().getContractList().size() != 1) {
throw new ContractSizeNotEqualToOneException(
String.format(
"tx %s contract size should be exactly 1, this is extend feature ,actual :%d",
txId, trxCap.getInstance().getRawData().getContractList().size()));
}

validateDup(trxCap);

if (!trxCap.validateSignature(chainBaseManager.getAccountStore(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.Protocol.Transaction.Contract;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result;
import org.tron.protos.Protocol.Transaction.Result.contractResult;
import org.tron.protos.Protocol.Transaction.raw;
import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract;
import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract;
Expand Down Expand Up @@ -237,4 +239,17 @@ private byte[] createContract()
Assert.assertNull(trace.getRuntimeError());
return trace.getRuntimeResult().getContractAddress();
}

@Test
public void testMaxContractResultSize() {
int maxSize = 0;
for (contractResult cr : contractResult.values()) {
if (cr.name().equals("UNRECOGNIZED")) {
continue;
}
Result result = Result.newBuilder().setContractRet(cr).build();
maxSize = Math.max(maxSize, result.getSerializedSize());
}
Assert.assertEquals(2, maxSize);
}
}
34 changes: 34 additions & 0 deletions framework/src/test/java/org/tron/core/BandwidthProcessorTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.tron.core;

import static org.junit.Assert.assertThrows;

import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.junit.Assert;
Expand All @@ -24,6 +27,11 @@
import org.tron.core.store.StoreFactory;
import org.tron.protos.Protocol;
import org.tron.protos.Protocol.AccountType;
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.Protocol.Transaction.Contract;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result;
import org.tron.protos.Protocol.Transaction.raw;
import org.tron.protos.contract.AssetIssueContractOuterClass.AssetIssueContract;
import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract;
import org.tron.protos.contract.BalanceContract.TransferContract;
Expand Down Expand Up @@ -540,6 +548,32 @@ public void testUsingFee() throws Exception {
dbManager.consumeBandwidth(trx, trace);
}

@Test
public void testConsumeBandwidthTooBigTransactionResultException() {
TransferContract transferContract =
TransferContract.newBuilder()
.setAmount(10)
.setOwnerAddress(ByteString.copyFromUtf8("aaa"))
.setToAddress(ByteString.copyFromUtf8("bbb"))
.build();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 6666; i++) {
sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
Transaction transaction = Transaction.newBuilder().setRawData(raw.newBuilder()
.setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8)))
.addContract(Contract.newBuilder().setParameter(Any.pack(transferContract))
.setType(ContractType.TransferContract)))
.addRet(Result.newBuilder().setAssetIssueID(sb.toString()).build()).build();
TransactionCapsule trx = new TransactionCapsule(transaction);
trx.setInBlock(false);
TransactionTrace trace = new TransactionTrace(trx, StoreFactory
.getInstance(), new RuntimeImpl());
assertThrows(
"Too big transaction result, TxId %s, the result size is %d bytes, maxResultSize %d",
TooBigTransactionResultException.class, () -> dbManager.consumeBandwidth(trx, trace));
}

/**
* sameTokenName close, consume success assetIssueCapsule.getOwnerAddress() !=
* fromAccount.getAddress()) contract.getType() = TransferAssetContract
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.tron.core.capsule;

import static org.tron.protos.Protocol.Transaction.Result.contractResult.BAD_JUMP_DESTINATION;
import static org.tron.protos.Protocol.Transaction.Result.contractResult.PRECOMPILED_CONTRACT;
import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS;

import com.google.protobuf.ByteString;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
Expand All @@ -13,8 +17,10 @@
import org.tron.core.config.args.Args;
import org.tron.protos.Protocol.AccountType;
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result;
import org.tron.protos.Protocol.Transaction.Result.contractResult;
import org.tron.protos.Protocol.Transaction.raw;

@Slf4j
public class TransactionCapsuleTest extends BaseTest {
Expand Down Expand Up @@ -1064,4 +1070,18 @@ public void trxCapsuleClearTest() {
Assert.assertEquals(trxCap.getInstance()
.getRet(0).getContractRet(), Result.contractResult.OUT_OF_TIME);
}

@Test
public void testRemoveRedundantRet() {
Transaction.Builder transaction = Transaction.newBuilder().setRawData(raw.newBuilder()
.addContract(Transaction.Contract.newBuilder().setType(ContractType.TriggerSmartContract))
.setFeeLimit(1000000000)).build().toBuilder();
transaction.addRet(Result.newBuilder().setContractRet(SUCCESS).build());
transaction.addRet(Result.newBuilder().setContractRet(PRECOMPILED_CONTRACT).build());
transaction.addRet(Result.newBuilder().setContractRet(BAD_JUMP_DESTINATION).build());
TransactionCapsule transactionCapsule = new TransactionCapsule(transaction.build());
transactionCapsule.removeRedundantRet();
Assert.assertEquals(1, transactionCapsule.getInstance().getRetCount());
Assert.assertEquals(SUCCESS, transactionCapsule.getInstance().getRet(0).getContractRet());
}
}
10 changes: 5 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 @@ -1131,24 +1131,24 @@ public void testTooBigTransaction() {
for (int i = 0; i < 6666; i++) {
sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
Transaction transaction = Transaction.newBuilder().setRawData(raw.newBuilder()
.setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8)))
.addContract(Transaction.Contract.newBuilder().setParameter(Any.pack(transferContract))
Transaction transaction = Transaction.newBuilder().setRawData(Transaction.raw.newBuilder()
.setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8)))
.addContract(Transaction.Contract.newBuilder().setParameter(Any.pack(transferContract))
.setType(ContractType.TransferContract))).build();
TransactionCapsule trx = new TransactionCapsule(transaction);
trx.setInBlock(false);
assertThrows(
"Too big transaction with result, "
+ "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, "
+ "the size is 533483 bytes, maxTxSize 512000",
TooBigTransactionException.class, ()-> dbManager.validateCommon(trx));
TooBigTransactionException.class, () -> dbManager.validateCommon(trx));

trx.setInBlock(true);
assertThrows(
"Too big transaction, "
+ "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, "
+ "the size is 1066643 bytes, maxTxSize 512000",
TooBigTransactionException.class, ()-> dbManager.validateCommon(trx));
TooBigTransactionException.class, () -> dbManager.validateCommon(trx));

}
}
1 change: 1 addition & 0 deletions protocol/src/main/protos/core/Tron.proto
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ message Transaction {
UNKNOWN = 13;
TRANSFER_FAILED = 14;
INVALID_CODE = 15;
// please fill in the order according to the serial number
}
int64 fee = 1;
code ret = 2;
Expand Down