Skip to content

Commit

Permalink
Merge pull request rsksmart#2627 from rsksmart/feature/introduce_init…
Browse files Browse the repository at this point in the history
…code_size_limit

Initial constants and config for the max initcode size
  • Loading branch information
Vovchyk authored Sep 19, 2024
2 parents 7dd58c6 + 1680ad6 commit 6fe81bb
Show file tree
Hide file tree
Showing 44 changed files with 1,536 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public TransactionValidationResult isValid(Transaction tx, Block executionBlock,
return TransactionValidationResult.withError("the sender account doesn't exist");
}

if(tx.isInitCodeSizeInvalidForTx(activationConfig.forBlock(bestBlockNumber))) {
return TransactionValidationResult.withError("transaction's init code size is invalid");
}

if (tx.getSize() > TX_MAX_SIZE) {
return TransactionValidationResult.withError(String.format("transaction's size is higher than defined maximum: %s > %s", tx.getSize(), TX_MAX_SIZE));
}
Expand Down
35 changes: 0 additions & 35 deletions rskj-core/src/main/java/co/rsk/net/handler/TxTimestamp.java

This file was deleted.

10 changes: 8 additions & 2 deletions rskj-core/src/main/java/org/ethereum/config/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class Constants {

private static final long DEFAULT_MAX_TIMESTAMPS_DIFF_IN_SECS = 5L * 60; // 5 mins
private static final long TESTNET_MAX_TIMESTAMPS_DIFF_IN_SECS = 120L * 60; // 120 mins
private static final long MAX_CONTRACT_SIZE = 0x6000;
private static final long MAX_INITCODE_SIZE = 2 * MAX_CONTRACT_SIZE;

private final byte chainId;
private final boolean seedCowAccounts;
Expand Down Expand Up @@ -213,8 +215,12 @@ public static BigInteger getTransactionGasCap() {
return TRANSACTION_GAS_CAP;
}

public static int getMaxContractSize() {
return 0x6000;
public static long getMaxContractSize() {
return MAX_CONTRACT_SIZE;
}

public static long getMaxInitCodeSize() {
return MAX_INITCODE_SIZE;
}

public static int getMaxAddressByteLength() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ public enum ConsensusRule {
RSKIP415("rskip415"),
RSKIP417("rskip417"),
RSKIP428("rskip428"),
RSKIP434("rskip434")
RSKIP434("rskip434"),
RSKIP438("rskip438")
;

private String configKey;
Expand Down
18 changes: 15 additions & 3 deletions rskj-core/src/main/java/org/ethereum/core/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
import co.rsk.metrics.profilers.ProfilerFactory;
import co.rsk.panic.PanicProcessor;
import co.rsk.peg.BridgeUtils;
import co.rsk.util.ListArrayUtil;
import org.bouncycastle.util.BigIntegers;
import org.ethereum.config.Constants;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
import org.ethereum.cost.InitcodeCostCalculator;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.ECKey.MissingPrivateKeyException;
import org.ethereum.crypto.HashUtil;
Expand All @@ -49,6 +49,7 @@
import java.security.SignatureException;
import java.util.Objects;

import static co.rsk.util.ListArrayUtil.getLength;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;

/**
Expand Down Expand Up @@ -203,15 +204,26 @@ public long transactionCost(Constants constants, ActivationConfig.ForBlock activ
}

long nonZeroes = this.nonZeroDataBytes();
long zeroVals = ListArrayUtil.getLength(this.getData()) - nonZeroes;
long zeroVals = getLength(this.getData()) - nonZeroes;

long transactionCost = this.isContractCreation() ? GasCost.TRANSACTION_CREATE_CONTRACT : GasCost.TRANSACTION;
long transactionCost = this.isContractCreation()
? GasCost.add(GasCost.TRANSACTION_CREATE_CONTRACT, InitcodeCostCalculator.getInstance().calculateCost(this.getData().length, activations))
: GasCost.TRANSACTION;

long txNonZeroDataCost = getTxNonZeroDataCost(activations);

return transactionCost + zeroVals * GasCost.TX_ZERO_DATA + nonZeroes * txNonZeroDataCost;
}


public boolean isInitCodeSizeInvalidForTx(ActivationConfig.ForBlock activations) {
int initCodeSize = getLength(this.getData());

return this.isContractCreation()
&& activations.isActive(ConsensusRule.RSKIP438)
&& initCodeSize > Constants.getMaxInitCodeSize();
}

private static long getTxNonZeroDataCost(ActivationConfig.ForBlock activations) {
return activations.isActive(ConsensusRule.RSKIP400) ? GasCost.TX_NO_ZERO_DATA_EIP2028 : GasCost.TX_NO_ZERO_DATA;
}
Expand Down
27 changes: 20 additions & 7 deletions rskj-core/src/main/java/org/ethereum/core/TransactionExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ private boolean init() {
return true;
}

if (tx.isInitCodeSizeInvalidForTx(activations)) {

String errorMessage = String.format("Initcode size for contract is invalid, it exceed the max limit size: initcode size = %d | maxAllowed = %d | tx = %s", getLength(tx.getData()), Constants.getMaxInitCodeSize(), tx.getHash());

logger.warn(errorMessage);

execError(errorMessage);

return false;
}

long txGasLimit = GasCost.toGas(tx.getGasLimit());
long curBlockGasLimit = GasCost.toGas(executionBlock.getGasLimit());

Expand All @@ -166,7 +177,6 @@ private boolean init() {
return false;
}


Coin totalCost = tx.getValue();

if (basicTxCost > 0 ) {
Expand Down Expand Up @@ -195,6 +205,7 @@ private boolean init() {
return true;
}


private boolean transactionAddressesAreValid() {
// Prevent transactions with excessive address size
byte[] receiveAddress = tx.getReceiveAddress().getBytes();
Expand Down Expand Up @@ -466,28 +477,30 @@ private void createContract() {
int createdContractSize = getLength(program.getResult().getHReturn());
long returnDataGasValue = GasCost.multiply(GasCost.CREATE_DATA, createdContractSize);
if (gasLeftover < returnDataGasValue) {
program.setRuntimeFailure(
configureRuntimeExceptionOnProgram(
Program.ExceptionHelper.notEnoughSpendingGas(
program,
"No gas to return just created contract",
returnDataGasValue));
result = program.getResult();
result.setHReturn(EMPTY_BYTE_ARRAY);
} else if (createdContractSize > Constants.getMaxContractSize()) {
program.setRuntimeFailure(
configureRuntimeExceptionOnProgram(
Program.ExceptionHelper.tooLargeContractSize(
program,
Constants.getMaxContractSize(),
createdContractSize));
result = program.getResult();
result.setHReturn(EMPTY_BYTE_ARRAY);
} else {
gasLeftover = GasCost.subtract(gasLeftover, returnDataGasValue);
program.spendGas(returnDataGasValue, "CONTRACT DATA COST");
cacheTrack.saveCode(tx.getContractAddress(), result.getHReturn());
}
}

private void configureRuntimeExceptionOnProgram(RuntimeException e) {
program.setRuntimeFailure(e);
result = program.getResult();
result.setHReturn(EMPTY_BYTE_ARRAY);
}

public TransactionReceipt getReceipt() {
if (receipt == null) {
receipt = new TransactionReceipt();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* This file is part of RskJ
* Copyright (C) 2022 RSK Labs Ltd.
* Copyright (C) 2024 RSK Labs Ltd.
* (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
Expand All @@ -16,15 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.ethereum.vm;
package org.ethereum.cost;

import org.junit.jupiter.api.BeforeEach;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;

class ProgramTestLogsOnOnTest extends ProgramTest {
public interface CostCalculator {

@BeforeEach
void beforeEach() {
setUp(true, true);
}

}
long calculateCost(long dataLength, ActivationConfig.ForBlock activations);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of RskJ
* Copyright (C) 2024 RSK Labs Ltd.
* (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.ethereum.cost;

import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;

import static org.ethereum.vm.GasCost.INITCODE_WORD_COST;

public class InitcodeCostCalculator implements CostCalculator {
private static InitcodeCostCalculator INSTANCE = new InitcodeCostCalculator();

private InitcodeCostCalculator() {}

public static InitcodeCostCalculator getInstance() {
return INSTANCE;
}

@Override
public long calculateCost(long dataLength, ActivationConfig.ForBlock activations) {
if ( dataLength > 0 && activations.isActive(ConsensusRule.RSKIP438) ) {
return INITCODE_WORD_COST * ( (long) Math.ceil( ( (double) dataLength ) / 32 ) );
}
return 0;
}
}
1 change: 1 addition & 0 deletions rskj-core/src/main/java/org/ethereum/vm/GasCost.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public class GasCost {
public static final long CODEREPLACE = 15000;
public static final long NEW_ACCT_SUICIDE = 25000;
public static final long RETURN = 0;
public static final long INITCODE_WORD_COST = 2;

public static final long MAX_GAS = Long.MAX_VALUE;

Expand Down
11 changes: 7 additions & 4 deletions rskj-core/src/main/java/org/ethereum/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.bouncycastle.util.BigIntegers;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.core.Repository;
import org.ethereum.cost.InitcodeCostCalculator;
import org.ethereum.crypto.HashUtil;
import org.ethereum.crypto.Keccak256Helper;
import org.ethereum.util.ByteUtil;
Expand Down Expand Up @@ -1440,17 +1441,18 @@ protected void doCREATE(){
throw Program.ExceptionHelper.modificationException(program);
}

DataWord size;
DataWord codeSize;
long sizeLong;
long newMemSize ;

if (computeGas) {
gasCost = GasCost.CREATE;
size = stack.get(stack.size() - 3);
sizeLong = Program.limitToMaxLong(size);
codeSize = stack.get(stack.size() - 3);
sizeLong = Program.limitToMaxLong(codeSize);
checkSizeArgument(sizeLong);
newMemSize = memNeeded(stack.get(stack.size() - 2), sizeLong);
gasCost = GasCost.add(gasCost, calcMemGas(oldMemSize, newMemSize, 0));
gasCost = GasCost.add(gasCost, InitcodeCostCalculator.getInstance().calculateCost(sizeLong, program.getActivations()));

spendOpCodeGas();
}
Expand Down Expand Up @@ -1484,7 +1486,8 @@ protected void doCREATE2(){
),
GasCost.SHA3_WORD,
GasCost.add(codeSize, 31) / 32
);
) ;
gasCost = GasCost.add(gasCost, InitcodeCostCalculator.getInstance().calculateCost(codeSize, program.getActivations()));
spendOpCodeGas();
}

Expand Down
Loading

0 comments on commit 6fe81bb

Please sign in to comment.