diff --git a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java index 326e2472757..08d0f5a8da5 100644 --- a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java @@ -38,6 +38,7 @@ import org.tron.core.utils.TransactionUtil; import org.tron.core.vm.EnergyCost; import org.tron.core.vm.LogInfoTriggerParser; +import org.tron.core.vm.Op; import org.tron.core.vm.OperationRegistry; import org.tron.core.vm.VM; import org.tron.core.vm.VMConstant; @@ -189,6 +190,13 @@ public void execute(Object object) throws ContractExeException { VM.play(program, OperationRegistry.getTable()); result = program.getResult(); + if (VMConfig.allowEnergyAdjustment()) { + // If the last op consumed too much execution time, the CPU time limit for the whole tx can be exceeded. + // This is not fair for other txs in the same block. + // So when allowFairEnergyAdjustment is on, the CPU time limit will be checked at the end of tx execution. + program.checkCPUTimeLimit(Op.getNameOf(program.getLastOp()) + "(TX_LAST_OP)"); + } + if (TrxType.TRX_CONTRACT_CREATION_TYPE == trxType && !result.isRevert()) { byte[] code = program.getResult().getHReturn(); if (code.length != 0 && VMConfig.allowTvmLondon() && code[0] == (byte) 0xEF) { diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java index cfec5b09d96..8f3501442f0 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -1,5 +1,7 @@ package org.tron.core.utils; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE; import static org.tron.core.Constant.DYNAMIC_ENERGY_INCREASE_FACTOR_RANGE; import static org.tron.core.Constant.DYNAMIC_ENERGY_MAX_FACTOR_RANGE; import static org.tron.core.config.Parameter.ChainConstant.ONE_YEAR_BLOCK_NUMBERS; @@ -748,6 +750,35 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case ALLOW_ENERGY_ADJUSTMENT: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]"); + } + if (dynamicPropertiesStore.getAllowEnergyAdjustment() == 1) { + throw new ContractValidateException( + "[ALLOW_ENERGY_ADJUSTMENT] has been valid, no need to propose again"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1"); + } + break; + } + case MAX_CREATE_ACCOUNT_TX_SIZE: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + throw new ContractValidateException( + "Bad chain parameter id [MAX_CREATE_ACCOUNT_TX_SIZE]"); + } + if (value < CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + || value > CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE) { + throw new ContractValidateException( + "This value[MAX_CREATE_ACCOUNT_TX_SIZE] is only allowed to be greater than or equal " + + "to " + CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + " and less than or equal to " + + CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE + "!"); + } + break; + } default: break; } @@ -824,7 +855,9 @@ public enum ProposalType { // current value, value range ALLOW_TVM_SHANGHAI(76), // 0, 1 ALLOW_CANCEL_ALL_UNFREEZE_V2(77), // 0, 1 MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000] - ALLOW_OLD_REWARD_OPT(79); // 0, 1 + ALLOW_OLD_REWARD_OPT(79), // 0, 1 + ALLOW_ENERGY_ADJUSTMENT(81), // 0, 1 + MAX_CREATE_ACCOUNT_TX_SIZE(82); // [500, 10000] private long code; diff --git a/actuator/src/main/java/org/tron/core/vm/EnergyCost.java b/actuator/src/main/java/org/tron/core/vm/EnergyCost.java index 3b62b2f549a..6638b22d47f 100644 --- a/actuator/src/main/java/org/tron/core/vm/EnergyCost.java +++ b/actuator/src/main/java/org/tron/core/vm/EnergyCost.java @@ -259,12 +259,19 @@ public static long getSuicideCost(Program ignored) { return SUICIDE; } + public static long getSuicideCost2(Program program) { + DataWord inheritorAddress = program.getStack().peek(); + if (isDeadAccount(program, inheritorAddress)) { + return getSuicideCost(program) + NEW_ACCT_CALL; + } + return getSuicideCost(program); + } + public static long getBalanceCost(Program ignored) { return BALANCE; } public static long getFreezeCost(Program program) { - Stack stack = program.getStack(); DataWord receiverAddressWord = stack.get(stack.size() - 3); if (isDeadAccount(program, receiverAddressWord)) { @@ -306,7 +313,27 @@ public static long getUnDelegateResourceCost(Program ignored) { } public static long getVoteWitnessCost(Program program) { + Stack stack = program.getStack(); + long oldMemSize = program.getMemSize(); + DataWord amountArrayLength = stack.get(stack.size() - 1).clone(); + DataWord amountArrayOffset = stack.get(stack.size() - 2); + DataWord witnessArrayLength = stack.get(stack.size() - 3).clone(); + DataWord witnessArrayOffset = stack.get(stack.size() - 4); + + DataWord wordSize = new DataWord(DataWord.WORD_SIZE); + + amountArrayLength.mul(wordSize); + BigInteger amountArrayMemoryNeeded = memNeeded(amountArrayOffset, amountArrayLength); + + witnessArrayLength.mul(wordSize); + BigInteger witnessArrayMemoryNeeded = memNeeded(witnessArrayOffset, witnessArrayLength); + + return VOTE_WITNESS + calcMemEnergy(oldMemSize, + (amountArrayMemoryNeeded.compareTo(witnessArrayMemoryNeeded) > 0 + ? amountArrayMemoryNeeded : witnessArrayMemoryNeeded), 0, Op.VOTEWITNESS); + } + public static long getVoteWitnessCost2(Program program) { Stack stack = program.getStack(); long oldMemSize = program.getMemSize(); DataWord amountArrayLength = stack.get(stack.size() - 1).clone(); @@ -317,9 +344,11 @@ public static long getVoteWitnessCost(Program program) { DataWord wordSize = new DataWord(DataWord.WORD_SIZE); amountArrayLength.mul(wordSize); + amountArrayLength.add(wordSize); // dynamic array length is at least 32 bytes BigInteger amountArrayMemoryNeeded = memNeeded(amountArrayOffset, amountArrayLength); witnessArrayLength.mul(wordSize); + witnessArrayLength.add(wordSize); // dynamic array length is at least 32 bytes BigInteger witnessArrayMemoryNeeded = memNeeded(witnessArrayOffset, witnessArrayLength); return VOTE_WITNESS + calcMemEnergy(oldMemSize, diff --git a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java index e4b1e174702..a2d3259ba89 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java @@ -67,6 +67,10 @@ public static JumpTable getTable() { adjustMemOperations(table); } + if (VMConfig.allowEnergyAdjustment()) { + adjustForFairEnergy(table); + } + return table; } @@ -635,4 +639,17 @@ public static void appendShangHaiOperations(JumpTable table) { OperationActions::push0Action, proposal)); } + + public static void adjustForFairEnergy(JumpTable table) { + table.set(new Operation( + Op.VOTEWITNESS, 4, 1, + EnergyCost::getVoteWitnessCost2, + OperationActions::voteWitnessAction, + VMConfig::allowTvmVote)); + + table.set(new Operation( + Op.SUICIDE, 1, 0, + EnergyCost::getSuicideCost2, + OperationActions::suicideAction)); + } } diff --git a/actuator/src/main/java/org/tron/core/vm/VMUtils.java b/actuator/src/main/java/org/tron/core/vm/VMUtils.java index abdf6c7fe4c..1df0e0e22f1 100644 --- a/actuator/src/main/java/org/tron/core/vm/VMUtils.java +++ b/actuator/src/main/java/org/tron/core/vm/VMUtils.java @@ -12,7 +12,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; -import java.util.Map; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import lombok.extern.slf4j.Slf4j; @@ -20,6 +19,7 @@ import org.tron.common.utils.ByteUtil; import org.tron.common.utils.Commons; import org.tron.common.utils.DecodeUtil; +import org.tron.core.Constant; import org.tron.core.capsule.AccountCapsule; import org.tron.core.exception.ContractValidateException; import org.tron.core.vm.config.VMConfig; @@ -33,6 +33,11 @@ public final class VMUtils { private VMUtils() { } + public static int getAddressSize() { + return VMConfig.allowEnergyAdjustment() ? + Constant.TRON_ADDRESS_SIZE : Constant.STANDARD_ADDRESS_SIZE; + } + public static void closeQuietly(Closeable closeable) { try { if (closeable != null) { diff --git a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java index 463d8c8995a..63c3ff791d6 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java +++ b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java @@ -39,6 +39,7 @@ public static void load(StoreFactory storeFactory) { VMConfig.initDynamicEnergyIncreaseFactor(ds.getDynamicEnergyIncreaseFactor()); VMConfig.initDynamicEnergyMaxFactor(ds.getDynamicEnergyMaxFactor()); VMConfig.initAllowTvmShangHai(ds.getAllowTvmShangHai()); + VMConfig.initAllowEnergyAdjustment(ds.getAllowEnergyAdjustment()); } } } diff --git a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java index 97202432598..3eb1f8fd4b8 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java +++ b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java @@ -49,6 +49,8 @@ public class VMConfig { private static boolean ALLOW_TVM_SHANGHAI = false; + private static boolean ALLOW_ENERGY_ADJUSTMENT = false; + private VMConfig() { } @@ -136,6 +138,10 @@ public static void initAllowTvmShangHai(long allow) { ALLOW_TVM_SHANGHAI = allow == 1; } + public static void initAllowEnergyAdjustment(long allow) { + ALLOW_ENERGY_ADJUSTMENT = allow == 1; + } + public static boolean getEnergyLimitHardFork() { return CommonParameter.ENERGY_LIMIT_HARD_FORK; } @@ -211,4 +217,8 @@ public static long getDynamicEnergyMaxFactor() { public static boolean allowTvmShanghai() { return ALLOW_TVM_SHANGHAI; } + + public static boolean allowEnergyAdjustment() { + return ALLOW_ENERGY_ADJUSTMENT; + } } diff --git a/actuator/src/main/java/org/tron/core/vm/program/Program.java b/actuator/src/main/java/org/tron/core/vm/program/Program.java index e02ba225c6b..0b0ef5bc9ba 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/Program.java +++ b/actuator/src/main/java/org/tron/core/vm/program/Program.java @@ -275,6 +275,10 @@ public void setLastOp(byte op) { this.lastOp = op; } + public byte getLastOp() { + return this.lastOp; + } + /** * Returns the last fully executed OP. */ @@ -457,7 +461,8 @@ public void suicide(DataWord obtainerAddress) { InternalTransaction internalTx = addInternalTx(null, owner, obtainer, balance, null, "suicide", nonce, getContractState().getAccount(owner).getAssetMapV2()); - if (FastByteComparisons.compareTo(owner, 0, 20, obtainer, 0, 20) == 0) { + int ADDRESS_SIZE = VMUtils.getAddressSize(); + if (FastByteComparisons.compareTo(owner, 0, ADDRESS_SIZE, obtainer, 0, ADDRESS_SIZE) == 0) { // if owner == obtainer just zeroing account according to Yellow Paper getContractState().addBalance(owner, -balance); byte[] blackHoleAddress = getContractState().getBlackHoleAddress(); 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 a588b28c748..c0a0fa4d88c 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -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; @@ -114,6 +115,9 @@ public class TransactionCapsule implements ProtoCapsule { @Getter @Setter private boolean isTransactionCreate = false; + @Getter + @Setter + private boolean isInBlock = false; public byte[] getOwnerAddress() { if (this.ownerAddress == null) { @@ -730,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; @@ -842,4 +855,18 @@ public BalanceContract.TransferContract getTransferContract() { return null; } } + + public void removeRedundantRet() { + Transaction tx = this.getInstance(); + List 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(); + } + } } 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 f13002f2dfa..3f0db86c537 100644 --- a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java @@ -1,8 +1,10 @@ package org.tron.core.db; +import static org.tron.core.Constant.PER_SIGN_LENGTH; import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.ShieldedTransferContract; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferAssetContract; +import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH; import com.google.protobuf.ByteString; import java.util.HashMap; @@ -19,13 +21,12 @@ import org.tron.core.capsule.TransactionCapsule; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; import org.tron.protos.contract.BalanceContract.TransferContract; -import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH; - @Slf4j(topic = "DB") public class BandwidthProcessor extends ResourceProcessor { @@ -95,8 +96,15 @@ public void updateUsage(AssetIssueCapsule assetIssueCapsule, long now) { @Override public void consume(TransactionCapsule trx, TransactionTrace trace) throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException { + TooBigTransactionResultException, TooBigTransactionException { List 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(); } @@ -127,6 +135,17 @@ public void consume(TransactionCapsule trx, TransactionTrace trace) } long now = chainBaseManager.getHeadSlot(); if (contractCreateNewAccount(contract)) { + if (!trx.isInBlock()) { + long maxCreateAccountTxSize = dynamicPropertiesStore.getMaxCreateAccountTxSize(); + int signatureCount = trx.getInstance().getSignatureCount(); + long createAccountBytesSize = trx.getInstance().toBuilder().clearRet() + .build().getSerializedSize() - (signatureCount * PER_SIGN_LENGTH); + if (createAccountBytesSize > maxCreateAccountTxSize) { + throw new TooBigTransactionException(String.format( + "Too big new account transaction, TxId %s, the size is %d bytes, maxTxSize %d", + trx.getTransactionId(), createAccountBytesSize, maxCreateAccountTxSize)); + } + } consumeForCreateNewAccount(accountCapsule, bytesSize, now, trace); continue; } diff --git a/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java b/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java index a7a22390958..c1875408850 100644 --- a/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java @@ -11,6 +11,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.BalanceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.store.AccountStore; import org.tron.core.store.DynamicPropertiesStore; @@ -35,7 +36,7 @@ protected ResourceProcessor(DynamicPropertiesStore dynamicPropertiesStore, } abstract void consume(TransactionCapsule trx, TransactionTrace trace) - throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException; + throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException, TooBigTransactionException; protected long increase(long lastUsage, long usage, long lastTime, long now) { return increase(lastUsage, usage, lastTime, now, windowSize); diff --git a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java index bf788232640..2b50ec76af2 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -219,6 +219,10 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_OLD_REWARD_OPT = "ALLOW_OLD_REWARD_OPT".getBytes(); + private static final byte[] ALLOW_ENERGY_ADJUSTMENT = "ALLOW_ENERGY_ADJUSTMENT".getBytes(); + + private static final byte[] MAX_CREATE_ACCOUNT_TX_SIZE = "MAX_CREATE_ACCOUNT_TX_SIZE".getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { super(dbName); @@ -2850,6 +2854,29 @@ public long getAllowOldRewardOpt() { .orElse(CommonParameter.getInstance().getAllowOldRewardOpt()); } + public void saveAllowEnergyAdjustment(long allowEnergyAdjustment) { + this.put(ALLOW_ENERGY_ADJUSTMENT, new BytesCapsule(ByteArray.fromLong(allowEnergyAdjustment))); + } + + public long getAllowEnergyAdjustment() { + return Optional.ofNullable(getUnchecked(ALLOW_ENERGY_ADJUSTMENT)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getAllowEnergyAdjustment()); + } + + public void saveMaxCreateAccountTxSize(long maxCreateAccountTxSize) { + this.put(MAX_CREATE_ACCOUNT_TX_SIZE, + new BytesCapsule(ByteArray.fromLong(maxCreateAccountTxSize))); + } + + public long getMaxCreateAccountTxSize() { + return Optional.ofNullable(getUnchecked(MAX_CREATE_ACCOUNT_TX_SIZE)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getMaxCreateAccountTxSize()); + } + private static class DynamicResourceProperties { private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes(); diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index f9562e580e3..22159063333 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -666,6 +666,14 @@ public class CommonParameter { @Setter public long allowOldRewardOpt; + @Getter + @Setter + public long allowEnergyAdjustment; + + @Getter + @Setter + public long maxCreateAccountTxSize = 1000L; + private static double calcMaxTimeRatio() { //return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1))); return 5.0; diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 2cd9ea95f15..0e634d3ef7d 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -18,12 +18,16 @@ public class Constant { public static final String ADD_PRE_FIX_STRING_MAINNET = "41"; public static final byte ADD_PRE_FIX_BYTE_TESTNET = (byte) 0xa0; //a0 + address public static final String ADD_PRE_FIX_STRING_TESTNET = "a0"; + public static final int STANDARD_ADDRESS_SIZE = 20; + public static final int TRON_ADDRESS_SIZE = 21; public static final int NODE_TYPE_FULL_NODE = 0; public static final int NODE_TYPE_LIGHT_NODE = 1; // config for transaction public static final long TRANSACTION_MAX_BYTE_SIZE = 500 * 1_024L; + public static final int CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE = 500; + public static final int CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE = 10000; public static final long MAXIMUM_TIME_UNTIL_EXPIRATION = 24 * 60 * 60 * 1_000L; //one day public static final long TRANSACTION_DEFAULT_EXPIRATION_TIME = 60 * 1_000L; //60 seconds public static final long TRANSACTION_FEE_POOL_PERIOD = 1; //1 blocks @@ -31,6 +35,8 @@ public class Constant { public static final long SUN_PER_ENERGY = 100; // 1 us = 100 SUN = 100 * 10^-6 TRX 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; @@ -376,4 +382,6 @@ public class Constant { public static final String MAX_UNSOLIDIFIED_BLOCKS = "node.maxUnsolidifiedBlocks"; public static final String COMMITTEE_ALLOW_OLD_REWARD_OPT = "committee.allowOldRewardOpt"; + + public static final String COMMITTEE_ALLOW_ENERGY_ADJUSTMENT = "committee.allowEnergyAdjustment"; } diff --git a/common/src/main/java/org/tron/core/config/Parameter.java b/common/src/main/java/org/tron/core/config/Parameter.java index 247826af77a..027c225eb5d 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -23,7 +23,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7(26, 1596780000000L, 80), VERSION_4_7_1(27, 1596780000000L, 80), VERSION_4_7_2(28, 1596780000000L, 80), - VERSION_4_7_4(29, 1596780000000L, 80); + VERSION_4_7_4(29, 1596780000000L, 80), + VERSION_4_7_5(30, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -72,7 +73,7 @@ public class ChainConstant { public static final int SINGLE_REPEAT = 1; public static final int BLOCK_FILLED_SLOTS_NUMBER = 128; public static final int MAX_FROZEN_NUMBER = 1; - public static final int BLOCK_VERSION = 29; + public static final int BLOCK_VERSION = 30; public static final long FROZEN_PERIOD = 86_400_000L; public static final long DELEGATE_PERIOD = 3 * 86_400_000L; public static final long TRX_PRECISION = 1000_000L; diff --git a/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java b/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java index 537fe49ae65..8d5697cdc89 100644 --- a/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java +++ b/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java @@ -91,6 +91,11 @@ private State produceBlock() { try { synchronized (dposService.getBlockHandle().getLock()) { + state = stateManager.getState(); + if (!State.OK.equals(state)) { + return state; + } + long slot = dposSlot.getSlot(System.currentTimeMillis() + 50); if (slot == 0) { return State.NOT_TIME_YET; diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 96af6fc7476..9d7eb75df1b 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -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) @@ -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) { @@ -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) @@ -1334,6 +1332,16 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getAllowOldRewardOpt()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowEnergyAdjustment") + .setValue(dbManager.getDynamicPropertiesStore().getAllowEnergyAdjustment()) + .build()); + + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getMaxCreateAccountTxSize") + .setValue(dbManager.getDynamicPropertiesStore().getMaxCreateAccountTxSize()) + .build()); + return builder.build(); } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index a8547b73948..422efefaed8 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -232,6 +232,7 @@ public static void clearParam() { PARAMETER.unsolidifiedBlockCheck = false; PARAMETER.maxUnsolidifiedBlocks = 54; PARAMETER.allowOldRewardOpt = 0; + PARAMETER.allowEnergyAdjustment = 0; } /** @@ -1205,6 +1206,10 @@ public static void setParam(final String[] args, final String confFileName) { } PARAMETER.allowOldRewardOpt = allowOldRewardOpt; + PARAMETER.allowEnergyAdjustment = + config.hasPath(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) ? config + .getInt(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) : 0; + logConfig(); } diff --git a/framework/src/main/java/org/tron/core/consensus/ProposalService.java b/framework/src/main/java/org/tron/core/consensus/ProposalService.java index 58da117cfc6..d0c106a7e57 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -359,6 +359,14 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveAllowOldRewardOpt(entry.getValue()); break; } + case ALLOW_ENERGY_ADJUSTMENT: { + manager.getDynamicPropertiesStore().saveAllowEnergyAdjustment(entry.getValue()); + break; + } + case MAX_CREATE_ACCOUNT_TX_SIZE: { + manager.getDynamicPropertiesStore().saveMaxCreateAccountTxSize(entry.getValue()); + break; + } default: find = false; break; 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 63bbef9ff7f..ef2f5c81124 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1,6 +1,7 @@ package org.tron.core.db; import static org.tron.common.utils.Commons.adjustBalance; +import static org.tron.core.Constant.TRANSACTION_MAX_BYTE_SIZE; import static org.tron.core.exception.BadBlockException.TypeEnum.CALC_MERKLE_ROOT_FAILED; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferContract; import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS; @@ -793,9 +794,22 @@ 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; + if (generalBytesSize > TRANSACTION_MAX_BYTE_SIZE) { + throw new TooBigTransactionException(String.format( + "Too big transaction with result, TxId %s, the size is %d bytes, maxTxSize %d", + transactionCapsule.getTransactionId(), generalBytesSize, TRANSACTION_MAX_BYTE_SIZE)); + } + } if (transactionCapsule.getData().length > Constant.TRANSACTION_MAX_BYTE_SIZE) { throw new TooBigTransactionException(String.format( - "Too big transaction, the size is %d bytes", transactionCapsule.getData().length)); + "Too big transaction, TxId %s, the size is %d bytes, maxTxSize %d", + transactionCapsule.getTransactionId(), transactionCapsule.getData().length, + TRANSACTION_MAX_BYTE_SIZE)); } long transactionExpiration = transactionCapsule.getExpiration(); long headBlockTime = chainBaseManager.getHeadBlockTimeStamp(); @@ -966,7 +980,7 @@ public void consumeMemoFee(TransactionCapsule trx, TransactionTrace trace) public void consumeBandwidth(TransactionCapsule trx, TransactionTrace trace) throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException { + TooBigTransactionResultException, TooBigTransactionException { BandwidthProcessor processor = new BandwidthProcessor(chainBaseManager); processor.consume(trx, trace); } @@ -1411,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, @@ -1422,18 +1442,12 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block if (Objects.nonNull(blockCap)) { chainBaseManager.getBalanceTraceStore().initCurrentTransactionBalanceTrace(trxCap); + trxCap.setInBlock(true); } 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(), diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java index 14523df86a5..926ed1a01ca 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java @@ -61,6 +61,18 @@ public void processMessage(PeerConnection peer, TronMessage msg) throws P2pExcep BlockMessage blockMessage = (BlockMessage) msg; BlockId blockId = blockMessage.getBlockId(); + BlockCapsule blockCapsule = blockMessage.getBlockCapsule(); + if (blockCapsule.getInstance().getSerializedSize() > maxBlockSize) { + logger.error("Receive bad block {} from peer {}, block size over limit", + blockMessage.getBlockId(), peer.getInetSocketAddress()); + throw new P2pException(TypeEnum.BAD_MESSAGE, "block size over limit"); + } + long gap = blockCapsule.getTimeStamp() - System.currentTimeMillis(); + if (gap >= BLOCK_PRODUCED_INTERVAL) { + logger.error("Receive bad block {} from peer {}, block time error", + blockMessage.getBlockId(), peer.getInetSocketAddress()); + throw new P2pException(TypeEnum.BAD_MESSAGE, "block time error"); + } if (!fastForward && !peer.isRelayPeer()) { check(peer, blockMessage); } @@ -109,18 +121,6 @@ private void check(PeerConnection peer, BlockMessage msg) throws P2pException { msg.getBlockId(), peer.getInetSocketAddress()); throw new P2pException(TypeEnum.BAD_MESSAGE, "no request"); } - BlockCapsule blockCapsule = msg.getBlockCapsule(); - if (blockCapsule.getInstance().getSerializedSize() > maxBlockSize) { - logger.error("Receive bad block {} from peer {}, block size over limit", - msg.getBlockId(), peer.getInetSocketAddress()); - throw new P2pException(TypeEnum.BAD_MESSAGE, "block size over limit"); - } - long gap = blockCapsule.getTimeStamp() - System.currentTimeMillis(); - if (gap >= BLOCK_PRODUCED_INTERVAL) { - logger.error("Receive bad block {} from peer {}, block time error", - msg.getBlockId(), peer.getInetSocketAddress()); - throw new P2pException(TypeEnum.BAD_MESSAGE, "block time error"); - } } private void processBlock(PeerConnection peer, BlockCapsule block) throws P2pException { @@ -150,14 +150,7 @@ private void processBlock(PeerConnection peer, BlockCapsule block) throws P2pExc try { tronNetDelegate.processBlock(block, false); - witnessProductBlockService.validWitnessProductTwoBlock(block); - - tronNetDelegate.getActivePeer().forEach(p -> { - if (p.getAdvInvReceive().getIfPresent(blockId) != null) { - p.setBlockBothHave(blockId); - } - }); } catch (Exception e) { logger.warn("Process adv block {} from peer {} failed. reason: {}", blockId, peer.getInetAddress(), e.getMessage()); diff --git a/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java b/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java index ea608c1ea86..505b53358c8 100644 --- a/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java +++ b/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java @@ -200,7 +200,6 @@ public void broadcast(Message msg) { logger.info("Ready to broadcast block {}", blockMsg.getBlockId().getString()); blockMsg.getBlockCapsule().getTransactions().forEach(transactionCapsule -> { Sha256Hash tid = transactionCapsule.getTransactionId(); - invToSpread.remove(tid); trxCache.put(new Item(tid, InventoryType.TRX), new TransactionMessage(transactionCapsule.getInstance())); }); diff --git a/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java b/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java index 889f6f6e132..bda2646abbc 100644 --- a/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java +++ b/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java @@ -71,9 +71,10 @@ public void fetchBlock(List sha256HashList, PeerConnection peer) { sha256HashList.stream().filter(sha256Hash -> new BlockCapsule.BlockId(sha256Hash).getNum() == chainBaseManager.getHeadBlockNum() + 1) .findFirst().ifPresent(sha256Hash -> { - fetchBlockInfo = new FetchBlockInfo(sha256Hash, peer, System.currentTimeMillis()); + long now = System.currentTimeMillis(); + fetchBlockInfo = new FetchBlockInfo(sha256Hash, peer, now); logger.info("Set fetchBlockInfo, block: {}, peer: {}, time: {}", sha256Hash, - fetchBlockInfo.getPeer().getInetAddress(), fetchBlockInfo.getTime()); + peer.getInetAddress(), now); }); } diff --git a/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java b/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java index 1e3e18441b9..9453700df0d 100644 --- a/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java +++ b/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java @@ -321,8 +321,9 @@ private void processSyncBlock(BlockCapsule block, PeerConnection peerConnection) } for (PeerConnection peer : tronNetDelegate.getActivePeer()) { - if (blockId.equals(peer.getSyncBlockToFetch().peek())) { - peer.getSyncBlockToFetch().pop(); + BlockId bid = peer.getSyncBlockToFetch().peek(); + if (blockId.equals(bid)) { + peer.getSyncBlockToFetch().remove(bid); if (flag) { peer.setBlockBothHave(blockId); if (peer.getSyncBlockToFetch().isEmpty() && peer.isFetchAble()) { diff --git a/framework/src/main/java/org/tron/program/Version.java b/framework/src/main/java/org/tron/program/Version.java index 483f5be713f..eb21aa292f7 100644 --- a/framework/src/main/java/org/tron/program/Version.java +++ b/framework/src/main/java/org/tron/program/Version.java @@ -2,9 +2,9 @@ public class Version { - public static final String VERSION_NAME = "GreatVoyage-v4.7.3.1-78-ge84a9e778"; - public static final String VERSION_CODE = "18260"; - private static final String VERSION = "4.7.4"; + public static final String VERSION_NAME = "GreatVoyage-v4.7.4-44-g8720e06a6"; + public static final String VERSION_CODE = "18306"; + private static final String VERSION = "4.7.5"; public static String getVersion() { return VERSION; diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java index afac8cd7d22..30bba35b43c 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java @@ -33,6 +33,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -154,7 +155,8 @@ public void testSuccess() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java index 7203388f815..0eef2266f9d 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java @@ -34,6 +34,7 @@ import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -156,7 +157,8 @@ public void testSuccess() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java index 40c5908c2dd..7debeb12772 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java @@ -35,6 +35,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -43,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; @@ -186,7 +189,8 @@ public void testSuccessNoBandd() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); @@ -235,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); + } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java index e359e7eab1a..4b3331187e2 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java @@ -34,6 +34,7 @@ import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -198,7 +199,7 @@ public void testSuccessNoBandWidth() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException, ContractExeException, ReceiptCheckErrException, - VMIllegalException { + VMIllegalException, TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java index be031d7c00b..2a70364b8d1 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java @@ -3,6 +3,8 @@ import static org.junit.Assert.assertEquals; import java.util.List; +import java.util.Random; + import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; @@ -15,6 +17,7 @@ import org.tron.common.BaseTest; import org.tron.common.parameter.CommonParameter; import org.tron.common.runtime.InternalTransaction; +import org.tron.common.utils.DecodeUtil; import org.tron.core.Constant; import org.tron.core.config.args.Args; import org.tron.core.exception.ContractValidateException; @@ -864,6 +867,73 @@ public void testPush0() throws ContractValidateException { VMConfig.initAllowTvmShangHai(0); } + @Test + public void testSuicideCost() throws ContractValidateException { + invoke = new ProgramInvokeMockImpl(StoreFactory.getInstance(), new byte[0], new byte[21]); + program = new Program(null, null, invoke, + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + + byte[] receiver1 = generateRandomAddress(); + program.stackPush(new DataWord(receiver1)); + Assert.assertEquals(0, EnergyCost.getSuicideCost(program)); + invoke.getDeposit().createAccount(receiver1, Protocol.AccountType.Normal); + Assert.assertEquals(0, EnergyCost.getSuicideCost(program)); + + byte[] receiver2 = generateRandomAddress(); + program.stackPush(new DataWord(receiver2)); + Assert.assertEquals(25000, EnergyCost.getSuicideCost2(program)); + invoke.getDeposit().createAccount(receiver2, Protocol.AccountType.Normal); + Assert.assertEquals(0, EnergyCost.getSuicideCost2(program)); + } + + @Test + public void testSuicideAction() throws ContractValidateException { + invoke = new ProgramInvokeMockImpl( + StoreFactory.getInstance(), + new byte[0], + Hex.decode("41471fd3ad3e9eeadeec4608b92d16ce6b500704cc")); + + program = new Program(null, null, invoke, + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + + VMConfig.initAllowEnergyAdjustment(1); + byte prePrefixByte = DecodeUtil.addressPreFixByte; + DecodeUtil.addressPreFixByte = Constant.ADD_PRE_FIX_BYTE_MAINNET; + + program.suicide(new DataWord( + dbManager.getAccountStore().getBlackhole().getAddress().toByteArray())); + + DecodeUtil.addressPreFixByte = prePrefixByte; + VMConfig.initAllowEnergyAdjustment(0); + } + + @Test + public void testVoteWitnessCost() throws ContractValidateException { + // Build stack environment, the stack from top to bottom is 0x00, 0x80, 0x00, 0x80 + program = new Program(null, null, new ProgramInvokeMockImpl(), + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + program.stackPush(DataWord.of((byte) 0x80)); + program.stackPush(DataWord.of((byte) 0x00)); + program.stackPush(DataWord.of((byte) 0x80)); + program.stackPush(DataWord.of((byte) 0x00)); + + // Test VoteWitness before EnergyAdjustment, should not have memory expand energy + Assert.assertEquals(30000, EnergyCost.getVoteWitnessCost(program)); + + // Test VoteWitness after EnergyAdjustment, should have memory expand energy + VMConfig.initAllowEnergyAdjustment(1); + + long memWords = (0x80 + 32) / 32; + long memoryExpandEnergy = 3 * memWords + memWords * memWords / 512; + Assert.assertEquals(30000 + memoryExpandEnergy, EnergyCost.getVoteWitnessCost2(program)); + } + private void testOperations(Program program) { try { while (!program.isStopped()) { @@ -954,4 +1024,10 @@ private byte[] compile(String code) { return new BytecodeCompiler().compile(code); } + private byte[] generateRandomAddress() { + byte[] address = new byte[21]; + new Random().nextBytes(address); + address[0] = DecodeUtil.addressPreFixByte; + return address; + } } diff --git a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java index 300c202e11a..1faa70d59ee 100755 --- a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java +++ b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java @@ -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; @@ -19,10 +22,16 @@ import org.tron.core.db.TransactionTrace; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; 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; @@ -539,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 @@ -646,6 +681,8 @@ public void sameTokenNameCloseConsumeSuccess() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); @@ -752,6 +789,8 @@ public void sameTokenNameOpenConsumeSuccess() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); @@ -821,6 +860,8 @@ public void sameTokenNameCloseTransferToAccountNotExist() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); diff --git a/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java index a42a4ffbe5a..7210fe8d074 100644 --- a/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java @@ -1,6 +1,10 @@ package org.tron.core.actuator; import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertThrows; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE; +import static org.tron.core.config.Parameter.ChainConstant.ONE_YEAR_BLOCK_NUMBERS; import com.google.protobuf.Any; import com.google.protobuf.ByteString; @@ -9,8 +13,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.tron.common.BaseTest; import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ForkController; import org.tron.core.Constant; import org.tron.core.Wallet; import org.tron.core.capsule.AccountCapsule; @@ -279,6 +285,50 @@ public void invalidPara() { Assert.assertEquals("This value[REMOVE_THE_POWER_OF_THE_GR] is only allowed to be 1", e.getMessage()); } + // verify Proposal No. 78 + paras = new HashMap<>(); + paras.put(78L, 10L); + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(dbManager.getChainBaseManager().getForkController()) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "Bad chain parameter id [MAX_DELEGATE_LOCK_PERIOD]", + ContractValidateException.class, actuator::validate); + + actuator = new ProposalCreateActuator(); + ForkController forkController = Mockito.mock(ForkController.class); + Mockito.when(forkController.pass(Mockito.any())).thenReturn(true); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(forkController) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + dbManager.getDynamicPropertiesStore().saveMaxDelegateLockPeriod(86400L); + long maxDelegateLockPeriod = dbManager.getDynamicPropertiesStore().getMaxDelegateLockPeriod(); + assertThrows( + "This value[MAX_DELEGATE_LOCK_PERIOD] is only allowed to be greater than " + + maxDelegateLockPeriod + " and less than or equal to " + ONE_YEAR_BLOCK_NUMBERS + "!", + ContractValidateException.class, actuator::validate); + + // verify Proposal No. 82 + paras = new HashMap<>(); + paras.put(82L, 0L); + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(dbManager.getChainBaseManager().getForkController()) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]", + ContractValidateException.class, actuator::validate); + + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(forkController) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "This value[MAX_CREATE_ACCOUNT_TX_SIZE] is only allowed to be greater than or equal " + + "to " + CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + " and less than or equal to " + + CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE + "!", + ContractValidateException.class, actuator::validate); } /** diff --git a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java index 8e2b7647967..db122f90c4f 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java @@ -3,7 +3,9 @@ import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; @@ -14,9 +16,11 @@ import org.tron.common.utils.ForkController; import org.tron.core.Constant; import org.tron.core.capsule.BytesCapsule; +import org.tron.core.capsule.ProposalCapsule; import org.tron.core.config.Parameter; import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.config.args.Args; +import org.tron.core.consensus.ProposalService; import org.tron.core.exception.ContractValidateException; import org.tron.core.store.DynamicPropertiesStore; import org.tron.core.utils.ProposalUtil; @@ -381,11 +385,75 @@ public void validateCheck() { e.getMessage()); } + testEnergyAdjustmentProposal(); + forkUtils.getManager().getDynamicPropertiesStore() .statsByVersion(ForkBlockVersionEnum.ENERGY_LIMIT.getValue(), stats); forkUtils.reset(); } + private void testEnergyAdjustmentProposal() { + // Should fail because cannot pass the fork controller check + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]", + e.getMessage()); + } + + long maintenanceTimeInterval = forkUtils.getManager().getDynamicPropertiesStore() + .getMaintenanceTimeInterval(); + + long hardForkTime = + ((ForkBlockVersionEnum.VERSION_4_7_5.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + forkUtils.getManager().getDynamicPropertiesStore() + .saveLatestBlockHeaderTimestamp(hardForkTime + 1); + + byte[] stats = new byte[27]; + Arrays.fill(stats, (byte) 1); + forkUtils.getManager().getDynamicPropertiesStore() + .statsByVersion(ForkBlockVersionEnum.VERSION_4_7_5.getValue(), stats); + + // Should fail because the proposal value is invalid + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 2); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1", + e.getMessage()); + } + + // Should succeed + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + } catch (Throwable t) { + Assert.fail(); + } + + ProposalCapsule proposalCapsule = new ProposalCapsule(ByteString.empty(), 0); + Map parameter = new HashMap<>(); + parameter.put(81L, 1L); + proposalCapsule.setParameters(parameter); + ProposalService.process(dbManager, proposalCapsule); + + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "[ALLOW_ENERGY_ADJUSTMENT] has been valid, no need to propose again", + e.getMessage()); + } + } + @Test public void blockVersionCheck() { for (ForkBlockVersionEnum forkVersion : ForkBlockVersionEnum.values()) { diff --git a/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java index fcb2a4fbfd5..17e9d3ac887 100644 --- a/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java +++ b/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java @@ -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; @@ -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 { @@ -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()); + } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 52307d9d294..5bbf08fd96e 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -101,6 +101,7 @@ public void get() { Assert.assertEquals(43, parameter.getNodeP2pVersion()); Assert.assertEquals(54, parameter.getMaxUnsolidifiedBlocks()); Assert.assertEquals(false, parameter.isUnsolidifiedBlockCheck()); + Assert.assertEquals(1000, parameter.getMaxCreateAccountTxSize()); //Assert.assertEquals(30, args.getSyncNodeCount()); // gRPC network configs checking diff --git a/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java b/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java new file mode 100644 index 00000000000..89d887d5fe9 --- /dev/null +++ b/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java @@ -0,0 +1,64 @@ +package org.tron.core.consensus; + +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.tron.consensus.base.BlockHandle; +import org.tron.consensus.base.State; +import org.tron.consensus.dpos.DposService; +import org.tron.consensus.dpos.DposSlot; +import org.tron.consensus.dpos.DposTask; +import org.tron.consensus.dpos.StateManager; + +public class DposTaskTest { + private DposTask dposTask = new DposTask(); + + @Test + public void tet() throws Exception { + StateManager stateManager = mock(StateManager.class); + Mockito.when(stateManager.getState()).thenReturn(State.BACKUP_IS_NOT_MASTER); + + Field field = dposTask.getClass().getDeclaredField("stateManager"); + field.setAccessible(true); + field.set(dposTask, stateManager); + + Method method = dposTask.getClass().getDeclaredMethod("produceBlock"); + method.setAccessible(true); + State state = (State) method.invoke(dposTask); + + Assert.assertEquals(State.BACKUP_IS_NOT_MASTER, state); + + + Mockito.when(stateManager.getState()).thenReturn(State.OK); + + DposSlot dposSlot = mock(DposSlot.class); + Mockito.when(dposSlot.getTime(1)).thenReturn(Long.MAX_VALUE); + + field = dposTask.getClass().getDeclaredField("dposSlot"); + field.setAccessible(true); + field.set(dposTask, dposSlot); + + + Mockito.when(stateManager.getState()).thenReturn(State.OK); + + BlockHandle blockHandle = mock(BlockHandle.class); + Mockito.when(blockHandle.getLock()).thenReturn(new Object()); + + + DposService dposService = mock(DposService.class); + Mockito.when(dposService.getBlockHandle()).thenReturn(blockHandle); + + field = dposTask.getClass().getDeclaredField("dposService"); + field.setAccessible(true); + field.set(dposTask, dposService); + + state = (State) method.invoke(dposTask); + + Assert.assertEquals(State.NOT_TIME_YET, state); + } + +} 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 053647cc25a..10cc766d8ed 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -1,5 +1,6 @@ package org.tron.core.db; +import static org.junit.Assert.assertThrows; import static org.tron.common.utils.Commons.adjustAssetBalanceV2; import static org.tron.common.utils.Commons.adjustBalance; import static org.tron.common.utils.Commons.adjustTotalShieldedPoolValue; @@ -8,8 +9,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -85,6 +88,7 @@ import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.Transaction.raw; import org.tron.protos.contract.AccountContract; import org.tron.protos.contract.AssetIssueContractOuterClass; import org.tron.protos.contract.BalanceContract.TransferContract; @@ -1114,4 +1118,37 @@ public void testExpireTransaction() { Assert.fail(); } } + + @Test + public void testTooBigTransaction() { + 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(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)); + + trx.setInBlock(true); + assertThrows( + "Too big transaction, " + + "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, " + + "the size is 1066643 bytes, maxTxSize 512000", + TooBigTransactionException.class, () -> dbManager.validateCommon(trx)); + + } } diff --git a/protocol/src/main/protos/core/Tron.proto b/protocol/src/main/protos/core/Tron.proto index 41ef968d907..2ffefbf9f3e 100644 --- a/protocol/src/main/protos/core/Tron.proto +++ b/protocol/src/main/protos/core/Tron.proto @@ -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;