mirror of https://github.com/hyperledger/besu
Implementation of EIP-2929 (#1387)
* store warmed addresses and slots i the MessageFrame * update gas calculations for berlin specific rules * allow state tests in EVMTool to override the forks. * retesteth should't broadcast re-orgs Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>pull/1413/head
parent
6034b89b54
commit
0f69337944
@ -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; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
# Case 1 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-1 |
||||
# |
||||
# This checks EXT(codehash,codesize,balance) of precompiles, which should be |
||||
# 100, and later checks the same operations twice against some non-precompiles. |
||||
# Those are cheaper second time they are accessed. Lastly, it checks the BALANCE |
||||
# of origin and this. |
||||
../../../build/install/evmtool/bin/evm \ |
||||
--Xberlin-enabled=true \ |
||||
--code=0x60013f5060023b506003315060f13f5060f23b5060f3315060f23f5060f33b5060f1315032315030315000 \ |
||||
--sender=0x0000000000000000000000000000000000000000 \ |
||||
--receiver=0x000000000000000000000000636F6E7472616374 \ |
||||
--chain=YOLO_V2 \ |
||||
--gas=9223372036854775807 \ |
||||
--repeat=10 |
||||
echo 'expect gasUser="0x21cd" (8653 dec)' |
||||
|
||||
# Case 2 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-2 |
||||
# |
||||
# This checks extcodecopy( 0xff,0,0,0,0) twice, (should be expensive first |
||||
# time), and then does extcodecopy( this,0,0,0,0) |
||||
../../../build/install/evmtool/bin/evm \ |
||||
--Xberlin-enabled=true \ |
||||
--code=0x60006000600060ff3c60006000600060ff3c600060006000303c00 \ |
||||
--sender=0x0000000000000000000000000000000000000000 \ |
||||
--receiver=0x000000000000000000000000636F6E7472616374 \ |
||||
--chain=YOLO_V2 \ |
||||
--gas=9223372036854775807 \ |
||||
--repeat=10 |
||||
echo 'expect gasUser="0xb13" (2835 dec)' |
||||
|
||||
# Case 3 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-3 |
||||
# |
||||
# This checks sload( 0x1) followed by sstore(loc: 0x01, val:0x11), then 'naked' |
||||
# sstore:sstore(loc: 0x02, val:0x11) twice, and sload(0x2), sload(0x1). |
||||
../../../build/install/evmtool/bin/evm \ |
||||
--Xberlin-enabled=true \ |
||||
--code=0x60015450601160015560116002556011600255600254600154 \ |
||||
--sender=0x0000000000000000000000000000000000000000 \ |
||||
--receiver=0x000000000000000000000000636F6E7472616374 \ |
||||
--chain=YOLO_V2 \ |
||||
--gas=9223372036854775807 \ |
||||
--repeat=10 |
||||
echo 'expect gasUser="0xadf1" (44529 dec)' |
||||
|
||||
# Case 4 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-4 |
||||
# |
||||
# This calls the identity-precompile (cheap), then calls an account (expensive) |
||||
# and staticcalls the same account (cheap) |
||||
../../../build/install/evmtool/bin/evm \ |
||||
--Xberlin-enabled=true \ |
||||
--code=0x60008080808060046000f15060008080808060ff6000f15060008080808060ff6000fa50 \ |
||||
--sender=0x0000000000000000000000000000000000000000 \ |
||||
--receiver=0x000000000000000000000000636F6E7472616374 \ |
||||
--chain=YOLO_V2 \ |
||||
--gas=9223372036854775807 \ |
||||
--repeat=10 |
||||
echo 'expect gasUser="0xb35" (2869 dec)' |
Loading…
Reference in new issue