Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of EIP-2929 #1387

Merged
merged 20 commits into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
## 1.6.0-RC1

### Additions and Improvements
* Added support for the upcoming YOLOv2 ephemeral testnet and removed the flag for the deprecated YOLOv1 ephemeral testnet.
* Added support for the upcoming YOLOv2 ephemeral testnet and removed the flag for the deprecated YOLOv1 ephemeral testnet. [#1386](https://github.com/hyperledger/besu/pull/1386)
* Added `debug_standardTraceBlockToFile` JSON-RPC API. This API accepts a block hash and will replay the block. It returns a list of files containing the result of the trace (one file per transaction). [\#1392](https://github.com/hyperledger/besu/pull/1392)
* Added support for EIP-2929 to YOLOv2. [#1387](https://github.com/hyperledger/besu/pull/1387)

### Bug Fixes

Expand Down
29 changes: 26 additions & 3 deletions ethereum/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ dependencies {
runtimeOnly 'org.apache.logging.log4j:log4j-core'

testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path:':ethereum:referencetests')
testImplementation project(path:':ethereum:referencetests', configuration: 'testOutput')
testImplementation project(path: ':ethereum:referencetests')
testImplementation project(path: ':ethereum:referencetests', configuration: 'testOutput')
testImplementation project(':testutil')

testImplementation 'junit:junit'
Expand Down Expand Up @@ -95,7 +95,7 @@ dependencies {
}

configurations { testArtifacts }
task testJar (type: Jar) {
task testJar(type: Jar) {
archiveBaseName = "${project.name}-test"
from sourceSets.test.output
}
Expand Down Expand Up @@ -147,6 +147,17 @@ task blockchainReferenceTestsSetup {
)
}

task legacyBlockchainReferenceTestsSetup {
generateTestFiles(
fileTree('../referencetests/src/test/resources/LegacyTests/Constantinople/BlockchainTests'),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTest.java.template"),
"LegacyTests",
"./src/test/java/org/hyperledger/besu/ethereum/vm/blockchain",
"LegacyBlockchainReferenceTest",
("BlockchainTests/InvalidBlocks/bcExpectSection") // exclude test for test filling tool
)
}

task generalstateReferenceTestsSetup {
generateTestFiles(
fileTree("../referencetests/src/test/resources/GeneralStateTests"),
Expand All @@ -157,6 +168,16 @@ task generalstateReferenceTestsSetup {
)
}

task legacyGeneralstateReferenceTestsSetup {
generateTestFiles(
fileTree('../referencetests/src/test/resources/LegacyTests/Constantinople/GeneralStateTests'),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTest.java.template"),
"LegacyTests",
"./src/test/java/org/hyperledger/besu/ethereum/vm/generalstate",
"LegacyGeneralStateReferenceTest"
)
}

task generalstateRegressionReferenceTestsSetup {
generateTestFiles(
fileTree("./src/test/resources/regressions/generalstate"),
Expand All @@ -180,6 +201,8 @@ clean.dependsOn(cleanupReferenceTests)
task referenceTests(type: Test, dependsOn: [
"blockchainReferenceTestsSetup",
"generalstateReferenceTestsSetup",
"legacyBlockchainReferenceTestsSetup",
"legacyGeneralstateReferenceTestsSetup",
"generalstateRegressionReferenceTestsSetup",
"compileTestJava"
]) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* 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 static org.hyperledger.besu.ethereum.core.Address.BLS12_MAP_FP2_TO_G2;

import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;

import org.apache.tuweni.units.bigints.UInt256;

public class BerlinGasCalculator extends IstanbulGasCalculator {

// new constants for EIP-2929
private static final Gas COLD_SLOAD_COST = Gas.of(2100);
private static final Gas COLD_ACCOUNT_ACCESS_COST = Gas.of(2600);
private static final Gas WARM_STORAGE_READ_COST = Gas.of(100);

// redefinitions for EIP-2929
private static final Gas SLOAD_GAS = WARM_STORAGE_READ_COST;
private static final Gas SSTORE_RESET_GAS = Gas.of(5000L).minus(COLD_SLOAD_COST);

// unchanged from Istanbul
private static final Gas SSTORE_SET_GAS = Gas.of(20_000);
private static final Gas SSTORE_CLEARS_SCHEDULE = Gas.of(15_000);

private static final Gas SSTORE_SET_GAS_LESS_SLOAD_GAS = SSTORE_SET_GAS.minus(SLOAD_GAS);
private static final Gas SSTORE_RESET_GAS_LESS_SLOAD_GAS = SSTORE_RESET_GAS.minus(SLOAD_GAS);
private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE);

// unchanged from Frontier
private static final Gas COPY_WORD_GAS_COST = Gas.of(3L);

private final int maxPrecompile;

protected BerlinGasCalculator(final int maxPrecompile) {
this.maxPrecompile = maxPrecompile;
}

public BerlinGasCalculator() {
this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]);
}

@Override
public boolean isPrecompile(final Address address) {
final byte[] addressBytes = address.toArrayUnsafe();
for (int i = 0; i < 19; i++) {
if (addressBytes[i] != 0) {
return false;
}
}
final int lastByte = Byte.toUnsignedInt(addressBytes[19]);
return lastByte <= maxPrecompile && lastByte != 0;
}

// new costs
@Override
public Gas getColdSloadCost() {
return COLD_SLOAD_COST;
}

@Override
public Gas getColdAccountAccessCost() {
return COLD_ACCOUNT_ACCESS_COST;
}

@Override
public Gas getWarmStorageReadCost() {
return WARM_STORAGE_READ_COST;
}

// Zeroed out old costs
@Override
public Gas getBalanceOperationGasCost() {
return Gas.ZERO;
}

@Override
protected Gas callOperationBaseGasCost() {
return Gas.ZERO;
}

@Override
public Gas extCodeHashOperationGasCost() {
return Gas.ZERO;
}

@Override
public Gas getExtCodeSizeOperationGasCost() {
return Gas.ZERO;
}

@Override
public Gas getSloadOperationGasCost() {
return Gas.ZERO;
}

// Redefined costs from EIP-2929
@Override
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
final Gas baseCost =
super.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
transferValue,
recipient,
to);
final boolean accountIsWarm = frame.warmUpAddress(to) || isPrecompile(to);
return baseCost.plus(accountIsWarm ? getWarmStorageReadCost() : getColdAccountAccessCost());
}

// defined in Frontier, but re-implemented with no base cost.
@Override
public Gas extCodeCopyOperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
return copyWordsToMemoryGasCost(frame, Gas.ZERO, COPY_WORD_GAS_COST, offset, length);
}

// defined in Istanbul, but re-implemented with new constants
@Override
// As per https://eips.ethereum.org/EIPS/eip-2200
public Gas calculateStorageCost(
final Account account, final UInt256 key, final UInt256 newValue) {

final UInt256 currentValue = account.getStorageValue(key);
if (currentValue.equals(newValue)) {
return SLOAD_GAS;
} else {
final UInt256 originalValue = account.getOriginalStorageValue(key);
if (originalValue.equals(currentValue)) {
return originalValue.isZero() ? SSTORE_SET_GAS : SSTORE_RESET_GAS;
} else {
return SLOAD_GAS;
}
}
}

// defined in Istanbul, but re-implemented with new constants
@Override
// As per https://eips.ethereum.org/EIPS/eip-2200
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;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;

import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
Expand Down Expand Up @@ -241,7 +242,8 @@ public Gas callOperationGasCost(
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =
Expand Down Expand Up @@ -446,7 +448,7 @@ public Gas getBeginSubGasCost() {
"BEGINSUB operation not supported by " + getClass().getSimpleName());
}

private Gas copyWordsToMemoryGasCost(
protected Gas copyWordsToMemoryGasCost(
final MessageFrame frame,
final Gas baseGasCost,
final Gas wordGasCost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ static ProtocolSpecBuilder berlinDefinition(
}
return muirGlacierDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason)
.gasCalculator(BerlinGasCalculator::new)
.evmBuilder(
gasCalculator ->
MainnetEvmRegistries.berlin(gasCalculator, chainId.orElse(BigInteger.ZERO)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;

import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
Expand All @@ -34,7 +35,8 @@ public Gas callOperationGasCost(
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;

import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
Expand Down Expand Up @@ -59,7 +60,8 @@ public Gas callOperationGasCost(
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) {
.returnStack(frame.getReturnStack())
.build();
frame.incrementRemainingGas(cost);
childFrame.mergeWarmedUpFields(frame);

frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED);
Expand Down Expand Up @@ -247,6 +248,7 @@ public void complete(final MessageFrame frame, final MessageFrame childFrame) {

frame.popStackItems(getStackItemsConsumed());
if (childFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
frame.mergeWarmedUpFields(childFrame);
frame.pushStackItem(UInt256.ONE.toBytes());
} else {
frame.pushStackItem(Bytes32.ZERO);
Expand Down
Loading