mirror of https://github.com/hyperledger/besu
parent
a388144f79
commit
3267501c8c
@ -0,0 +1,84 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.mainnet; |
||||
|
||||
import org.hyperledger.besu.ethereum.core.Account; |
||||
import org.hyperledger.besu.ethereum.core.Gas; |
||||
|
||||
import org.apache.tuweni.units.bigints.UInt256; |
||||
|
||||
public class LondonGasCalculator extends BerlinGasCalculator { |
||||
|
||||
// redefinitions for EIP-3529
|
||||
private static final Gas SSTORE_CLEARS_SCHEDULE = SSTORE_RESET_GAS.plus(ACCESS_LIST_STORAGE_COST); |
||||
|
||||
private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE); |
||||
|
||||
// redefinitions for EIP-3529
|
||||
private static final int NEW_MAX_REFUND_QUOTIENT = 5; |
||||
|
||||
protected LondonGasCalculator() {} |
||||
|
||||
// Redefined refund amount from EIP-3529
|
||||
@Override |
||||
public Gas getSelfDestructRefundAmount() { |
||||
return Gas.ZERO; |
||||
} |
||||
|
||||
// defined in Berlin, but re-implemented with new constants
|
||||
@Override |
||||
// As per https://eips.ethereum.org/EIPS/eip-3529
|
||||
public Gas calculateStorageRefundAmount( |
||||
final Account account, final UInt256 key, final UInt256 newValue) { |
||||
final UInt256 currentValue = account.getStorageValue(key); |
||||
if (currentValue.equals(newValue)) { |
||||
return Gas.ZERO; |
||||
} else { |
||||
final UInt256 originalValue = account.getOriginalStorageValue(key); |
||||
if (originalValue.equals(currentValue)) { |
||||
if (originalValue.isZero()) { |
||||
return Gas.ZERO; |
||||
} else if (newValue.isZero()) { |
||||
return SSTORE_CLEARS_SCHEDULE; |
||||
} else { |
||||
return Gas.ZERO; |
||||
} |
||||
} else { |
||||
Gas refund = Gas.ZERO; |
||||
if (!originalValue.isZero()) { |
||||
if (currentValue.isZero()) { |
||||
refund = NEGATIVE_SSTORE_CLEARS_SCHEDULE; |
||||
} else if (newValue.isZero()) { |
||||
refund = SSTORE_CLEARS_SCHEDULE; |
||||
} |
||||
} |
||||
|
||||
if (originalValue.equals(newValue)) { |
||||
refund = |
||||
refund.plus( |
||||
originalValue.isZero() |
||||
? SSTORE_SET_GAS_LESS_SLOAD_GAS |
||||
: SSTORE_RESET_GAS_LESS_SLOAD_GAS); |
||||
} |
||||
return refund; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public long getMaxRefundQuotient() { |
||||
return NEW_MAX_REFUND_QUOTIENT; |
||||
}; |
||||
} |
@ -0,0 +1,106 @@ |
||||
/* |
||||
* Copyright 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.vm.operations; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.config.StubGenesisConfigOptions; |
||||
import org.hyperledger.besu.config.experimental.ExperimentalEIPs; |
||||
import org.hyperledger.besu.ethereum.core.Account; |
||||
import org.hyperledger.besu.ethereum.core.Gas; |
||||
import org.hyperledger.besu.ethereum.core.TestCodeExecutor; |
||||
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; |
||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; |
||||
import org.hyperledger.besu.ethereum.vm.MessageFrame; |
||||
import org.hyperledger.besu.ethereum.vm.MessageFrame.State; |
||||
|
||||
import org.apache.tuweni.units.bigints.UInt256; |
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.junit.runners.Parameterized; |
||||
import org.junit.runners.Parameterized.Parameter; |
||||
import org.junit.runners.Parameterized.Parameters; |
||||
|
||||
@RunWith(Parameterized.class) |
||||
public class LondonSStoreOperationGasCostTest { |
||||
|
||||
private static ProtocolSchedule protocolSchedule; |
||||
|
||||
@Parameters(name = "Code: {0}, Original: {1}") |
||||
public static Object[][] scenarios() { |
||||
// Tests specified in EIP-3539.
|
||||
return new Object[][] { |
||||
{"0x60006000556000600055", 0, 212, 0}, |
||||
{"0x60006000556001600055", 0, 20112, 0}, |
||||
{"0x60016000556000600055", 0, 20112, 19900}, |
||||
{"0x60016000556002600055", 0, 20112, 0}, |
||||
{"0x60016000556001600055", 0, 20112, 0}, |
||||
{"0x60006000556000600055", 1, 3012, 4800}, |
||||
{"0x60006000556001600055", 1, 3012, 2800}, |
||||
{"0x60006000556002600055", 1, 3012, 0}, |
||||
{"0x60026000556000600055", 1, 3012, 4800}, |
||||
{"0x60026000556003600055", 1, 3012, 0}, |
||||
{"0x60026000556001600055", 1, 3012, 2800}, |
||||
{"0x60026000556002600055", 1, 3012, 0}, |
||||
{"0x60016000556000600055", 1, 3012, 4800}, |
||||
{"0x60016000556002600055", 1, 3012, 0}, |
||||
{"0x60016000556001600055", 1, 212, 0}, |
||||
{"0x600160005560006000556001600055", 0, 40118, 19900}, |
||||
{"0x600060005560016000556000600055", 1, 5918, 7600}, |
||||
}; |
||||
} |
||||
|
||||
private TestCodeExecutor codeExecutor; |
||||
|
||||
@Parameter public String code; |
||||
|
||||
@Parameter(value = 1) |
||||
public int originalValue; |
||||
|
||||
@Parameter(value = 2) |
||||
public int expectedGasUsed; |
||||
|
||||
@Parameter(value = 3) |
||||
public int expectedGasRefund; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
ExperimentalEIPs.eip1559Enabled = true; |
||||
protocolSchedule = |
||||
MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().londonBlock(0)); |
||||
codeExecutor = new TestCodeExecutor(protocolSchedule); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldCalculateGasAccordingToEip3529() { |
||||
final long gasLimit = 1_000_000; |
||||
final MessageFrame frame = |
||||
codeExecutor.executeCode( |
||||
code, |
||||
Account.DEFAULT_VERSION, |
||||
gasLimit, |
||||
account -> account.setStorageValue(UInt256.ZERO, UInt256.valueOf(originalValue))); |
||||
assertThat(frame.getState()).isEqualTo(State.COMPLETED_SUCCESS); |
||||
assertThat(frame.getRemainingGas()).isEqualTo(Gas.of(gasLimit - (expectedGasUsed + 2100))); |
||||
assertThat(frame.getGasRefund()).isEqualTo(Gas.of(expectedGasRefund)); |
||||
} |
||||
|
||||
@After |
||||
public void reset() { |
||||
ExperimentalEIPs.eip1559Enabled = ExperimentalEIPs.EIP1559_ENABLED_DEFAULT_VALUE; |
||||
} |
||||
} |
Loading…
Reference in new issue