From 49243ab445b2603b9eef727b5b84d3e715cf69b0 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 23 Jul 2019 16:32:34 -0600 Subject: [PATCH] [PAN-2756] EIP-2028 - Reduce intrinsic gas cost (#1739) Reduce the non-zero byte of intrinsic gas cost from 68 to 16. Keep all other values the same. Signed-off-by: Adrian Sutton --- .../mainnet/IstanbulGasCalculator.java | 48 ++++++++ .../mainnet/MainnetProtocolSpecs.java | 2 +- .../core/ExecutionContextTestFixture.java | 2 +- .../ethereum/mainnet/IntrinsicGasTest.java | 114 ++++++++++++++++++ 4 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/IstanbulGasCalculator.java create mode 100644 ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/IntrinsicGasTest.java diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/IstanbulGasCalculator.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/IstanbulGasCalculator.java new file mode 100644 index 0000000000..3090616765 --- /dev/null +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/IstanbulGasCalculator.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.mainnet; + +import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Transaction; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +public class IstanbulGasCalculator extends ConstantinopleFixGasCalculator { + + private static final Gas TX_DATA_ZERO_COST = Gas.of(4L); + private static final Gas TX_DATA_NON_ZERO_COST = Gas.of(16L); + private static final Gas TX_BASE_COST = Gas.of(21_000L); + + @Override + public Gas transactionIntrinsicGasCost(final Transaction transaction) { + final BytesValue payload = transaction.getPayload(); + int zeros = 0; + for (int i = 0; i < payload.size(); i++) { + if (payload.get(i) == 0) { + ++zeros; + } + } + final int nonZeros = payload.size() - zeros; + + Gas cost = + Gas.ZERO + .plus(TX_BASE_COST) + .plus(TX_DATA_ZERO_COST.times(zeros)) + .plus(TX_DATA_NON_ZERO_COST.times(nonZeros)); + + if (transaction.isContractCreation()) { + cost = cost.plus(txCreateExtraGasCost()); + } + + return cost; + } +} diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java index a5f92bd6f1..9a2f162708 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java @@ -292,7 +292,7 @@ public abstract class MainnetProtocolSpecs { final int stackSizeLimit = configStackSizeLimit.orElse(DEFAULT_MAX_STACK_SIZE); return constantinopleFixDefinition( chainId, configContractSizeLimit, configStackSizeLimit, enableRevertReason) - .gasCalculator(ConstantinopleGasCalculator::new) + .gasCalculator(IstanbulGasCalculator::new) .evmBuilder(gasCalculator -> MainnetEvmRegistries.istanbul(gasCalculator, chainId.get())) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul) .transactionProcessorBuilder( diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 7cef8004b0..8263349f54 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -110,7 +110,7 @@ public class ExecutionContextTestFixture { if (protocolSchedule == null) { protocolSchedule = new ProtocolScheduleBuilder<>( - new StubGenesisConfigOptions().istanbulBlock(0), + new StubGenesisConfigOptions().constantinopleFixBlock(0), BigInteger.valueOf(42), Function.identity(), new PrivacyParameters(), diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/IntrinsicGasTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/IntrinsicGasTest.java new file mode 100644 index 0000000000..ae744bb7f3 --- /dev/null +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/IntrinsicGasTest.java @@ -0,0 +1,114 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.mainnet; + +import static org.assertj.core.api.Assertions.assertThat; + +import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Transaction; +import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.ethereum.vm.GasCalculator; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class IntrinsicGasTest { + + private final GasCalculator gasCalculator; + private final Gas expectedGas; + private final String txRlp; + + public IntrinsicGasTest( + final GasCalculator gasCalculator, final Gas expectedGas, final String txRlp) { + this.gasCalculator = gasCalculator; + this.expectedGas = expectedGas; + this.txRlp = txRlp; + } + + @Parameters + public static Collection data() { + final GasCalculator frontier = new FrontierGasCalculator(); + final GasCalculator istanbul = new IstanbulGasCalculator(); + return Arrays.asList( + new Object[][] { + // EnoughGAS + { + frontier, + Gas.of(21952), + "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + { + istanbul, + Gas.of(21224), + "0xf86d80018259d894095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + // FirstZeroBytes + { + frontier, + Gas.of(21180), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + { + istanbul, + Gas.of(21128), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000010000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + // LastZeroBytes + { + frontier, + Gas.of(21180), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + { + istanbul, + Gas.of(21128), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d01000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + // NotEnoughGAS + { + frontier, + Gas.of(21952), + "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + { + istanbul, + Gas.of(21224), + "0xf86d800182521c94095e7baea6a6c7c4c2dfeb977efac326af552d870a8e0358ac39584bc98a7c979f984b031ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + // ZeroBytes + { + frontier, + Gas.of(21116), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + { + istanbul, + Gas.of(21116), + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + }, + }); + } + + @Test + public void validateGasCost() { + Transaction t = Transaction.readFrom(RLP.input(BytesValue.fromHexString(txRlp))); + assertThat(gasCalculator.transactionIntrinsicGasCost(t)).isEqualTo(expectedGas); + } +}