Skip to content

Commit

Permalink
Merge pull request #2030 from rsksmart/EIP-2028
Browse files Browse the repository at this point in the history
EIP-2028: calldata gas cost reduction
  • Loading branch information
Vovchyk authored Sep 27, 2023
2 parents 3dcbb52 + 6fb0f13 commit b05236e
Show file tree
Hide file tree
Showing 18 changed files with 73 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public enum ConsensusRule {
RSKIP383("rskip383"),
RSKIP385("rskip385"),
RSKIP398("rskip398"),
RSKIP400("rskip400"), // From EIP-2028 calldata gas cost reduction
;

private String configKey;
Expand Down
11 changes: 10 additions & 1 deletion rskj-core/src/main/java/org/ethereum/core/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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.crypto.ECKey;
import org.ethereum.crypto.ECKey.MissingPrivateKeyException;
import org.ethereum.crypto.HashUtil;
Expand Down Expand Up @@ -204,7 +205,15 @@ public long transactionCost(Constants constants, ActivationConfig.ForBlock activ
long nonZeroes = this.nonZeroDataBytes();
long zeroVals = ListArrayUtil.getLength(this.getData()) - nonZeroes;

return (this.isContractCreation() ? GasCost.TRANSACTION_CREATE_CONTRACT : GasCost.TRANSACTION) + zeroVals * GasCost.TX_ZERO_DATA + nonZeroes * GasCost.TX_NO_ZERO_DATA;
long transactionCost = this.isContractCreation() ? GasCost.TRANSACTION_CREATE_CONTRACT : GasCost.TRANSACTION;

long txNonZeroDataCost = getTxNonZeroDataCost(activations);

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

private static long getTxNonZeroDataCost(ActivationConfig.ForBlock activations) {
return activations.isActive(ConsensusRule.RSKIP400) ? GasCost.TX_NO_ZERO_DATA_EIP2028 : GasCost.TX_NO_ZERO_DATA;
}

public void verify(SignatureCache signatureCache) {
Expand Down
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 @@ -74,6 +74,7 @@ public class GasCost {
public static final long CREATE_DATA = 200; // paid for each new byte of code
public static final long REPLACE_DATA = 50; // paid for each byte of code replaced
public static final long TX_NO_ZERO_DATA = 68;
public static final long TX_NO_ZERO_DATA_EIP2028 = 16; // https://eips.ethereum.org/EIPS/eip-2028
public static final long TX_ZERO_DATA = 4;
public static final long TRANSACTION = 21000;
public static final long TRANSACTION_DEFAULT = 90000; //compatibility with ethereum (mmarquez)
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/expected.conf
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ blockchain = {
rskip383 = <hardforkName>
rskip385 = <hardforkName>
rskip398 = <hardforkName>
rskip400 = <hardforkName>
}
}
gc = {
Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ blockchain = {
rskip383 = fingerroot500
rskip385 = fingerroot500
rskip398 = tbd600
rskip400 = tbd600
}
}
gc = {
Expand Down
29 changes: 29 additions & 0 deletions rskj-core/src/test/java/co/rsk/core/TransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import co.rsk.peg.RepositoryBtcBlockStoreWithCache;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
import org.ethereum.config.Constants;
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
import org.ethereum.config.blockchain.upgrades.ConsensusRule;
import org.ethereum.core.*;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
Expand All @@ -37,12 +40,14 @@
import org.ethereum.vm.program.ProgramResult;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.math.BigInteger;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.mockito.Mockito.mock;

class TransactionTest {

Expand Down Expand Up @@ -436,5 +441,29 @@ void createEncodeAndDecodeTransactionWithChainId() {
Assertions.assertEquals(Transaction.LOWER_REAL_V, transaction.getSignature().getV());
Assertions.assertEquals (Transaction.CHAIN_ID_INC + chainId * 2, transaction.getEncodedV());
}

@Test
void testTransactionCostWithRSKIP400Disabled() {
byte[] bytes = new byte[]{-8, 96, -128, 8, -126, -61, 80, -108, -31, 126, -117, -65, -39, -94, 75, -27, 104, -101, 13, -118, 50, 8, 31, -83, -40, -94, 59, 107, 7, -127, -1, 102, -96, -63, -110, 91, -2, 42, -19, 18, 4, 67, -64, 48, -45, -85, -123, 41, 14, -48, -124, 118, 21, -63, -39, -45, 67, 116, -103, 93, 37, 4, 88, -61, 49, -96, 77, -30, -116, 59, -58, -82, -95, 76, 46, 124, 115, -32, -80, 125, 30, -42, -75, -111, -49, -41, 121, -73, -121, -68, -41, 72, -120, 94, 82, 42, 17, 61};
Transaction txInBlock = new ImmutableTransaction(bytes);

Constants constants = Mockito.mock(Constants.class);
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
Mockito.doReturn(false).when(activations).isActive(Mockito.eq(ConsensusRule.RSKIP400));

Assertions.assertEquals(21068L, txInBlock.transactionCost(constants, activations, new BlockTxSignatureCache(new ReceivedTxSignatureCache())));
}

@Test
void testTransactionCostWithRSKIP400Enabled() {
byte[] bytes = new byte[]{-8, 96, -128, 8, -126, -61, 80, -108, -31, 126, -117, -65, -39, -94, 75, -27, 104, -101, 13, -118, 50, 8, 31, -83, -40, -94, 59, 107, 7, -127, -1, 102, -96, -63, -110, 91, -2, 42, -19, 18, 4, 67, -64, 48, -45, -85, -123, 41, 14, -48, -124, 118, 21, -63, -39, -45, 67, 116, -103, 93, 37, 4, 88, -61, 49, -96, 77, -30, -116, 59, -58, -82, -95, 76, 46, 124, 115, -32, -80, 125, 30, -42, -75, -111, -49, -41, 121, -73, -121, -68, -41, 72, -120, 94, 82, 42, 17, 61};
Transaction txInBlock = new ImmutableTransaction(bytes);

Constants constants = Mockito.mock(Constants.class);
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
Mockito.doReturn(true).when(activations).isActive(Mockito.eq(ConsensusRule.RSKIP400));

Assertions.assertEquals(21016L, txInBlock.transactionCost(constants, activations, new BlockTxSignatureCache(new ReceivedTxSignatureCache())));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,17 @@ void testGasEstimation() {
BigInteger nonce = repository.getAccountState(srcAddr).getNonce();
RskAddress contractAddress = new RskAddress(HashUtil.calcNewAddr(srcAddr.getBytes(), nonce.toByteArray()));
int gasLimit = 5000000; // start with 5M
int consumed = checkEstimateGas(callCallWithValue, 33472 + GasCost.STIPEND_CALL, gasLimit, srcAddr, contractAddress, web3, repository);
int consumed = checkEstimateGas(callCallWithValue, 33264 + GasCost.STIPEND_CALL, gasLimit, srcAddr, contractAddress, web3, repository);

// Now that I know the estimation, call again using the estimated value
// it should not fail. We set the gasLimit to the expected value plus 1 to
// differentiate between OOG and success.
int consumed2 = checkEstimateGas(callCallWithValue, 33472 + GasCost.STIPEND_CALL, consumed + 1, srcAddr, contractAddress, web3, repository);
int consumed2 = checkEstimateGas(callCallWithValue, 33264 + GasCost.STIPEND_CALL, consumed + 1, srcAddr, contractAddress, web3, repository);

Assertions.assertEquals(consumed, consumed2);

consumed = checkEstimateGas(callUnfill, 46942, gasLimit, srcAddr, contractAddress, web3, repository);
consumed2 = checkEstimateGas(callUnfill, 46942, consumed + 1, srcAddr, contractAddress, web3, repository);
consumed = checkEstimateGas(callUnfill, 46734, gasLimit, srcAddr, contractAddress, web3, repository);
consumed2 = checkEstimateGas(callUnfill, 46734, consumed + 1, srcAddr, contractAddress, web3, repository);

Assertions.assertEquals(consumed, consumed2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void invalidIntrinsicGasPrice() {
.builder()
.nonce(BigInteger.ZERO)
.gasPrice(BigInteger.ZERO)
.gasLimit(BigInteger.valueOf(21071))
.gasLimit(BigInteger.valueOf(21019))
.destination(new ECKey().getAddress())
.data(Hex.decode("0001"))
.chainId(Constants.REGTEST_CHAIN_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ void processMinersFeesFromTxInvokedByAnotherContract() {
// remasc.call();
// }
// }
long txCreateContractGasLimit = 53755 + 32000;
long txCreateContractGasLimit = 46995 + 32000;
Transaction txCreateContract = Transaction
.builder()
.nonce(Coin.valueOf(1))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void testEstimateGas_contractCallsWithValueTransfer() throws FileNotFoundExcepti

// Estimate the gas to use
long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(35728, estimatedGas);
assertEquals(35520, estimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -195,7 +195,7 @@ void testEstimateGas_storageRefunds() throws FileNotFoundException, DslProcessor

long clearStorageGasUsed = callConstantResult.getGasUsed();
long clearStorageEstimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(26909, clearStorageEstimatedGas);
assertEquals(26649, clearStorageEstimatedGas);

assertTrue(eth.getEstimationResult().getDeductedRefund() > 0);

Expand All @@ -220,7 +220,7 @@ void testEstimateGas_storageRefunds() throws FileNotFoundException, DslProcessor
"0000000000000000000000000000000000000000000000000000000000000001"); // setValue(1,1)
long updateStorageGasUsed = eth.callConstant(args, block).getGasUsed();
long updateStorageEstimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(26973, updateStorageEstimatedGas);
assertEquals(26661, updateStorageEstimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -255,7 +255,7 @@ void testEstimateGas_storageRefunds() throws FileNotFoundException, DslProcessor
ProgramResult anotherCallConstantResult = eth.callConstant(args, block);
long anotherClearStorageGasUsed = anotherCallConstantResult.getGasUsed();
long anotherClearStorageEstimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(26909, anotherClearStorageEstimatedGas);
assertEquals(26649, anotherClearStorageEstimatedGas);

assertTrue(eth.getEstimationResult().getDeductedRefund() > 0);

Expand Down Expand Up @@ -325,7 +325,7 @@ void estimateGas_callWithValuePlusSStoreRefund() throws FileNotFoundException, D
long callConstantGasUsed = callConstant.getGasUsed();

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(40771, estimatedGas);
assertEquals(40563, estimatedGas);

assertTrue(estimatedGas > callConstantGasUsed);
assertEquals(callConstant.getMaxGasUsed() + GasCost.STIPEND_CALL, estimatedGas);
Expand Down Expand Up @@ -401,7 +401,7 @@ void estimateGas_nestedCallsWithValueAndGasRetain() throws FileNotFoundException
long callConstantGasUsed = callConstant.getGasUsed();

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(48841, estimatedGas);
assertEquals(48633, estimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -477,7 +477,7 @@ void estimateGas_subsequentCallWithValueAndGasStipendCase1() throws FileNotFound
assertTrue(callConstant.isCallWithValuePerformed());

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(39459, estimatedGas);
assertEquals(39251, estimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -550,7 +550,7 @@ void estimateGas_subsequentCallWithValueAndGasStipendCase2() throws FileNotFound
assertTrue(callConstant.isCallWithValuePerformed());

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(48674, estimatedGas);
assertEquals(48466, estimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -603,7 +603,7 @@ void estimateGas_firstCallMoveAllRemainingSecondNot() throws FileNotFoundExcepti

// Estimate the gas to use
long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(34996, estimatedGas);
assertEquals(34788, estimatedGas);

assertEquals(0, eth.getEstimationResult().getDeductedRefund());

Expand Down Expand Up @@ -684,7 +684,7 @@ void estimateGas_nestedCallsWithValueGasRetainAndStorageRefund() throws FileNotF
long callConstantGasUsed = callConstant.getGasUsed();

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(84210, estimatedGas);
assertEquals(84002, estimatedGas);

assertTrue(eth.getEstimationResult().getDeductedRefund() > 0);

Expand Down Expand Up @@ -760,7 +760,7 @@ void estimateGas_nestedCallsWithValueFixedGasRetainAndStorageRefund() throws Fil
long callConstantGasUsed = callConstant.getGasUsed();

long estimatedGas = estimateGas(eth, args, BlockTag.LATEST.getTag());
assertEquals(84200, estimatedGas);
assertEquals(83992, estimatedGas);

assertTrue(eth.getEstimationResult().getDeductedRefund() > 0);

Expand Down
2 changes: 1 addition & 1 deletion rskj-core/src/test/java/co/rsk/test/DslFilesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void runCreate01Resource() throws FileNotFoundException, DslProcessorException {

Assertions.assertNotEquals(BigInteger.ZERO, gasUsed);
// According to TestRPC and geth, the gas used is 0x010c2d
Assertions.assertEquals(BigIntegers.fromUnsignedByteArray(Hex.decode("010c2d")), gasUsed);
Assertions.assertEquals(BigIntegers.fromUnsignedByteArray(Hex.decode("fd59")), gasUsed);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ActivationConfigTest {
" rskip383: fingerroot500",
" rskip385: fingerroot500",
" rskip398: tbd600",
" rskip400: tbd600",
"}"
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Web3ImplLogsTest {
private static final String ONE_TOPIC = "0000000000000000000000000000000000000000000000000000000000000001";
private static final String INCREMENT_METHOD_SIGNATURE = "371303c0";
private static final String GET_VALUE_METHOD_SIGNATURE = "20965255";
private static final String TRACKED_TEST_BLOCK_HASH = "0xafb368a4f74e51a3c6b6d72b049c4fc7bc7506251f13a3afa4fee4bece0e85eb";
private static final String TRACKED_TEST_BLOCK_HASH = "0x8eac2053d453195bfede97c77ee215b64bf47c8bdcecc75c67a8aa6f7c66f173";
private static final String UNTRACKED_TEST_BLOCK_HASH = "0xdea168a4f74e51a3eeb6d72b049c4fc7bc750dd51f13a3afa4fee4bece0e85eb";
private final TestSystemProperties config = new TestSystemProperties();

Expand Down
4 changes: 2 additions & 2 deletions rskj-core/src/test/resources/dsl/contracts03.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ assert_best b04
assert_balance tx01 10000

# check sender balance, before next transaction
assert_balance acc1 8557429
assert_balance acc1 8618789

transaction_build tx05
sender acc1
Expand All @@ -112,7 +112,7 @@ assert_best b05
assert_balance tx01 10000

# check sender balance, it should pay the total cost (8589589 - 25000)
assert_balance acc1 8532429
assert_balance acc1 8593789

transaction_build tx06
sender acc1
Expand Down
2 changes: 1 addition & 1 deletion rskj-core/src/test/resources/dsl/contracts05.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ assert_best b01
assert_balance 0000000000000000000000000000000000000002 5000

# Gas applied (10000000 - 21344 - 5000)
assert_balance acc1 9973656
assert_balance acc1 9973864

6 changes: 3 additions & 3 deletions rskj-core/src/test/resources/dsl/opcode_revert1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ block_connect b01
# Assert best block
assert_best b01

assert_balance acc1 9857039
assert_balance acc1 9873263

transaction_build tx02
sender acc1
Expand All @@ -40,7 +40,7 @@ block_connect b02
assert_best b02

# spend 99527 gas running the contract
assert_balance acc1 9756792
assert_balance acc1 9773224

transaction_build tx03
sender acc1
Expand All @@ -62,4 +62,4 @@ block_connect b03
assert_best b03

# spend only 21424 because the contract uses the revert OPCODE
assert_balance acc1 9735368
assert_balance acc1 9752008
6 changes: 3 additions & 3 deletions rskj-core/src/test/resources/dsl/opcode_revert2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ block_connect b01
# Assert best block
assert_best b01

assert_balance acc1 9857039
assert_balance acc1 9873263

transaction_build tx02
sender acc1
Expand All @@ -40,7 +40,7 @@ block_connect b02
assert_best b02

# spend only 21424 because the contract uses the revert OPCODE
assert_balance acc1 9835615
assert_balance acc1 9852047

transaction_build tx03
sender acc1
Expand All @@ -62,4 +62,4 @@ block_connect b03
assert_best b03

# spend 99527 gas running the contract
assert_balance acc1 9735368
assert_balance acc1 9752008
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@
},
"transaction" : {
"data" : "0x600a80600c6000396000f200600160008035811a8100",
"gasLimit" : "0xd2f0",
"gasLimit" : "0xcf7c",
"gasPrice" : "0x03",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
Expand Down

0 comments on commit b05236e

Please sign in to comment.