Skip to content

Commit

Permalink
Wire up EIP-3860 - Limit and Meter Initcode to shanghaiTime
Browse files Browse the repository at this point in the history
Used new contractSizeLimit (from shandong) but using PrefixCodeRule instead of CachedInvalidCodeRule since we don't want EOF enabled yet.

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
  • Loading branch information
siladu committed Dec 14, 2022
1 parent a47cce6 commit 36add07
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
Expand Up @@ -52,6 +52,7 @@
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator;
import org.hyperledger.besu.evm.gascalculator.ShandongGasCalculator;
import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.gascalculator.TangerineWhistleGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
Expand Down Expand Up @@ -81,6 +82,7 @@ public abstract class MainnetProtocolSpecs {
public static final int FRONTIER_CONTRACT_SIZE_LIMIT = Integer.MAX_VALUE;

public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576;
public static final int SHANGHAI_CONTRACT_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT;
public static final int SHANDONG_CONTRACT_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT;

private static final Address RIPEMD160_PRECOMPILE =
Expand Down Expand Up @@ -649,6 +651,7 @@ static ProtocolSpecBuilder shanghaiDefinition(

final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
final BaseFeeMarket baseFeeMarket = getBaseFeeMarket(genesisConfigOptions);
final int contractSizeLimit = configContractSizeLimit.orElse(SHANGHAI_CONTRACT_SIZE_LIMIT);

return parisDefinition(
chainId,
Expand All @@ -658,6 +661,7 @@ static ProtocolSpecBuilder shanghaiDefinition(
genesisConfigOptions,
quorumCompatibilityMode,
evmConfiguration)
.gasCalculator(ShanghaiGasCalculator::new)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
MainnetEVMs.shanghai(
Expand All @@ -677,6 +681,15 @@ static ProtocolSpecBuilder shanghaiDefinition(
stackSizeLimit,
baseFeeMarket,
CoinbaseFeePriceCalculator.eip1559()))
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), PrefixCodeRule.of()),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.withdrawalsProcessorBuilder(WithdrawalsProcessor.AllowedWithdrawalsProcessor::new)
.withdrawalsValidatorBuilder(WithdrawalsValidator.AllowedWithdrawals::new)
.name("Shanghai");
Expand Down
Expand Up @@ -17,6 +17,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs.SHANDONG_CONTRACT_SIZE_LIMIT;
import static org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs.SHANGHAI_CONTRACT_SIZE_LIMIT;
import static org.hyperledger.besu.evm.MainnetEVMs.DEV_NET_CHAIN_ID;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -73,6 +74,7 @@ public class CreateOperationTest {
+ "F3" // RETURN
);
public static final String SENDER = "0xdeadc0de00000000000000000000000000000000";
private static final int SHANGHAI_CREATE_GAS = 41240;
private static final int SHANDONG_CREATE_GAS = 41240;

@Test
Expand Down Expand Up @@ -178,6 +180,63 @@ public void notEnoughValue() {
assertThat(messageFrame.getStackItem(0)).isEqualTo(UInt256.ZERO);
}

@Test
public void shanghaiMaxInitCodeSizeCreate() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.valueOf(SHANGHAI_CONTRACT_SIZE_LIMIT);
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);

when(account.getMutable()).thenReturn(mutableAccount);
when(account.getNonce()).thenReturn(55L);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getSenderAccount(any())).thenReturn(account);
when(worldUpdater.getOrCreate(any())).thenReturn(newAccount);
when(newAccount.getMutable()).thenReturn(newMutableAccount);
when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY);
when(worldUpdater.updater()).thenReturn(worldUpdater);

final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = operation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrameStack.peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);

final Log log = createFrame.getLogs().get(0);
final String calculatedTopic = log.getTopics().get(0).toUnprefixedHexString();
assertThat(calculatedTopic).isEqualTo(TOPIC);
assertThat(result.getGasCost()).isEqualTo(SHANGHAI_CREATE_GAS);
}

@Test
public void shanghaiMaxInitCodeSizePlus1Create() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.valueOf(SHANGHAI_CONTRACT_SIZE_LIMIT + 1);
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);

when(account.getMutable()).thenReturn(mutableAccount);
when(account.getNonce()).thenReturn(55L);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getSenderAccount(any())).thenReturn(account);
when(worldUpdater.getOrCreate(any())).thenReturn(newAccount);
when(newAccount.getMutable()).thenReturn(newMutableAccount);
when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY);
when(worldUpdater.updater()).thenReturn(worldUpdater);

final EVM evm = MainnetEVMs.shandong(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = operation.execute(messageFrame, evm);
assertThat(messageFrame.getStackItem(0)).isEqualTo(UInt256.ZERO);
assertThat(result.getGasCost()).isEqualTo(SHANGHAI_CREATE_GAS);
}

@Test
public void shandongMaxInitCodeSizeCreate() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
Expand Down
4 changes: 4 additions & 0 deletions evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
Expand Up @@ -427,6 +427,10 @@ public static void registerParisOperations(
registry.put(new PrevRanDaoOperation(gasCalculator));
}

public static EVM shanghai(final BigInteger chainId, final EvmConfiguration evmConfiguration) {
return shanghai(new LondonGasCalculator(), chainId, evmConfiguration);
}

public static EVM shanghai(
final GasCalculator gasCalculator,
final BigInteger chainId,
Expand Down
@@ -0,0 +1,48 @@
package org.hyperledger.besu.evm.gascalculator;
/*
* Copyright contributors to Hyperledger Besu.
*
* 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
*/

import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;

import org.hyperledger.besu.evm.frame.MessageFrame;

import org.apache.tuweni.bytes.Bytes;

public class ShanghaiGasCalculator extends LondonGasCalculator {

private static final long INIT_CODE_COST = 2L;

@Override
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) {
long intrinsicGasCost = super.transactionIntrinsicGasCost(payload, isContractCreation);
if (isContractCreation) {
return clampedAdd(intrinsicGasCost, calculateInitGasCost(payload.size()));
} else {
return intrinsicGasCost;
}
}

@Override
public long createOperationGasCost(final MessageFrame frame) {
final long initCodeLength = clampedToLong(frame.getStackItem(2));
return clampedAdd(super.createOperationGasCost(frame), calculateInitGasCost(initCodeLength));
}

private static long calculateInitGasCost(final long initCodeLength) {
final int dataLength = (int) Math.ceil(initCodeLength / 32.0);
return dataLength * INIT_CODE_COST;
}
}

0 comments on commit 36add07

Please sign in to comment.