diff --git a/build.gradle b/build.gradle index 9c9bb68939b..9e687f6b44f 100644 --- a/build.gradle +++ b/build.gradle @@ -168,7 +168,7 @@ configure(allprojects - project(':platform')) { def ethExecSpecTestsRepo = ivy { url 'https://github.com' patternLayout { - artifact '/[organisation]/[module]/releases/download/v[revision]/[classifier].[ext]' + artifact '/[organisation]/[module]/releases/download/[revision]/[classifier].[ext]' } metadataSources { artifact() diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java index 146ef2c722d..2d6af314fc6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java @@ -84,6 +84,6 @@ protected long getGasLimit(final PrivateTransaction privateTransaction, final St // choose the highest of the two options return Math.max( privateTransaction.getGasLimit(), - gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false)); + gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false, 0)); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java index ecf1da973f3..12a8d4d33c9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/CodeDelegation.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationTransactionEncoder; +import org.hyperledger.besu.ethereum.core.json.ChainIdDeserializer; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import java.math.BigInteger; @@ -28,10 +29,14 @@ import java.util.function.Supplier; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.common.base.Suppliers; import org.apache.tuweni.bytes.Bytes; +// ignore `signer` field used in execution-spec-tests +@JsonIgnoreProperties(ignoreUnknown = true) public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelegation { private static final Supplier SIGNATURE_ALGORITHM = Suppliers.memoize(SignatureAlgorithmFactory::getInstance); @@ -77,14 +82,23 @@ public CodeDelegation( */ @JsonCreator public static org.hyperledger.besu.datatypes.CodeDelegation createCodeDelegation( - @JsonProperty("chainId") final BigInteger chainId, + @JsonProperty("chainId") @JsonDeserialize(using = ChainIdDeserializer.class) + final BigInteger chainId, @JsonProperty("address") final Address address, - @JsonProperty("nonce") final long nonce, - @JsonProperty("v") final byte v, - @JsonProperty("r") final BigInteger r, - @JsonProperty("s") final BigInteger s) { + @JsonProperty("nonce") final String nonce, + @JsonProperty("v") final String v, + @JsonProperty("r") final String r, + @JsonProperty("s") final String s) { return new CodeDelegation( - chainId, address, nonce, SIGNATURE_ALGORITHM.get().createSignature(r, s, v)); + chainId, + address, + Bytes.fromHexStringLenient(nonce).toLong(), + SIGNATURE_ALGORITHM + .get() + .createSignature( + Bytes.fromHexStringLenient(r).toUnsignedBigInteger(), + Bytes.fromHexStringLenient(s).toUnsignedBigInteger(), + Bytes.fromHexStringLenient(v).get(0))); } @JsonProperty("chainId") diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java index 04be922ecd2..f2c3b11a79c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java @@ -35,12 +35,7 @@ public ChainIdDeserializer(final Class vc) { @Override public BigInteger deserialize(final JsonParser jsonparser, final DeserializationContext context) throws IOException { - final var chainId = - UInt256.fromHexString(jsonparser.getCodec().readValue(jsonparser, String.class)) - .toBigInteger(); - if (chainId.signum() <= 0) { - throw new IllegalArgumentException("Non positive chain id: " + chainId); - } - return chainId; + return UInt256.fromHexString(jsonparser.getCodec().readValue(jsonparser, String.class)) + .toBigInteger(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index 47c1747dc95..ab3f8250cdc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -171,12 +171,14 @@ public static ProtocolSpecBuilder atlantisDefinition( evm, true, Collections.singletonList(MaxCodeSizeRule.from(evm)), 1)) .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, @@ -353,12 +355,14 @@ public static ProtocolSpecBuilder spiralDefinition( // EIP-3651 .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index af71df1ab5a..f0a411ad868 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -70,6 +70,8 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.processor.MessageCallProcessor; +import org.hyperledger.besu.evm.refundcalculator.FrontierRefundCalculator; +import org.hyperledger.besu.evm.refundcalculator.PragueRefundCalculator; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -118,6 +120,7 @@ public static ProtocolSpecBuilder frontierDefinition( final MetricsSystem metricsSystem) { return new ProtocolSpecBuilder() .gasCalculator(FrontierGasCalculator::new) + .refundCalculator(FrontierRefundCalculator::new) .gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator()) .evmBuilder(MainnetEVMs::frontier) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::frontier) @@ -132,12 +135,14 @@ public static ProtocolSpecBuilder frontierDefinition( evm.getGasCalculator(), gasLimitCalculator, false, Optional.empty())) .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, @@ -293,12 +298,14 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( evm.getGasCalculator(), gasLimitCalculator, true, chainId)) .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor, @@ -499,12 +506,14 @@ static ProtocolSpecBuilder londonDefinition( Integer.MAX_VALUE)) .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, @@ -631,12 +640,14 @@ static ProtocolSpecBuilder shanghaiDefinition( // we need to flip the Warm Coinbase flag for EIP-3651 warm coinbase .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, @@ -718,12 +729,14 @@ static ProtocolSpecBuilder cancunDefinition( // use Cancun fee market .transactionProcessorBuilder( (gasCalculator, + refundCalculator, feeMarket, transactionValidator, contractCreationProcessor, messageCallProcessor) -> new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor, @@ -837,6 +850,7 @@ static ProtocolSpecBuilder pragueDefinition( metricsSystem) .feeMarket(pragueFeeMarket) .gasCalculator(pragueGasCalcSupplier) + .refundCalculator(PragueRefundCalculator::new) // EIP-7840 Blob schedule | EIP-7691 6/9 blob increase .gasLimitCalculatorBuilder( feeMarket -> diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index f559ec327a6..e41a2bf9a17 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -18,6 +18,7 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER; import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION; import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import org.hyperledger.besu.collections.trie.BytesTrieSet; import org.hyperledger.besu.datatypes.AccessListEntry; @@ -41,6 +42,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.processor.AbstractMessageProcessor; +import org.hyperledger.besu.evm.refundcalculator.RefundCalculator; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.EVMWorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -66,6 +68,8 @@ public class MainnetTransactionProcessor { protected final GasCalculator gasCalculator; + private final RefundCalculator refundCalculator; + protected final TransactionValidatorFactory transactionValidatorFactory; private final AbstractMessageProcessor contractCreationProcessor; @@ -85,6 +89,7 @@ public class MainnetTransactionProcessor { public MainnetTransactionProcessor( final GasCalculator gasCalculator, + final RefundCalculator refundCalculator, final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, @@ -95,6 +100,7 @@ public MainnetTransactionProcessor( final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) { this( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, @@ -108,6 +114,7 @@ public MainnetTransactionProcessor( public MainnetTransactionProcessor( final GasCalculator gasCalculator, + final RefundCalculator refundCalculator, final TransactionValidatorFactory transactionValidatorFactory, final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor messageCallProcessor, @@ -118,6 +125,7 @@ public MainnetTransactionProcessor( final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator, final CodeDelegationProcessor maybeCodeDelegationProcessor) { this.gasCalculator = gasCalculator; + this.refundCalculator = refundCalculator; this.transactionValidatorFactory = transactionValidatorFactory; this.contractCreationProcessor = contractCreationProcessor; this.messageCallProcessor = messageCallProcessor; @@ -372,22 +380,22 @@ public TransactionProcessingResult processTransaction( warmAddressList.add(miningBeneficiary); } - final long intrinsicGas = - gasCalculator.transactionIntrinsicGasCost( - transaction.getPayload(), transaction.isContractCreation()); final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); final long codeDelegationGas = gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()); - final long gasAvailable = - transaction.getGasLimit() - intrinsicGas - accessListGas - codeDelegationGas; + final long intrinsicGas = + gasCalculator.transactionIntrinsicGasCost( + transaction.getPayload(), + transaction.isContractCreation(), + clampedAdd(accessListGas, codeDelegationGas)); + + final long gasAvailable = transaction.getGasLimit() - intrinsicGas; LOG.trace( - "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - codeDelegation)", + "Gas available for execution {} = {} - {} (limit - intrinsic)", gasAvailable, transaction.getGasLimit(), - intrinsicGas, - accessListGas, - codeDelegationGas); + intrinsicGas); final WorldUpdater worldUpdater = evmWorldUpdater.updater(); final ImmutableMap.Builder contextVariablesBuilder = @@ -500,11 +508,9 @@ public TransactionProcessingResult processTransaction( // Refund the sender by what we should and pay the miner fee (note that we're doing them one // after the other so that if it is the same account somehow, we end up with the right result) - final long selfDestructRefund = - gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size(); - final long baseRefundGas = - initialFrame.getGasRefund() + selfDestructRefund + codeDelegationRefund; - final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas); + final long refundedGas = + refundCalculator.calculateGasRefund( + gasCalculator, transaction, initialFrame, codeDelegationRefund); final Wei refundedWei = transactionGasPrice.multiply(refundedGas); final Wei balancePriorToRefund = sender.getBalance(); sender.incrementBalance(refundedWei); @@ -635,15 +641,6 @@ public AbstractMessageProcessor getMessageProcessor(final MessageFrame.Type type }; } - protected long refunded( - final Transaction transaction, final long gasRemaining, final long gasRefund) { - // Integer truncation takes care of the floor calculation needed after the divide. - final long maxRefundAllowance = - (transaction.getGasLimit() - gasRemaining) / gasCalculator.getMaxRefundQuotient(); - final long refundAllowance = Math.min(maxRefundAllowance, gasRefund); - return gasRemaining + refundAllowance; - } - private String printableStackTraceFromThrowable(final RuntimeException re) { final StringBuilder builder = new StringBuilder(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 2b9fea0f3d0..1cd8995c21f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import static org.hyperledger.besu.evm.account.Account.MAX_NONCE; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -252,17 +253,22 @@ private ValidationResult validateCostAndFee( } } - final long intrinsicGasCost = - gasCalculator.transactionIntrinsicGasCost( - transaction.getPayload(), transaction.isContractCreation()) - + (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L)) - + gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()); - if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) { + final long baselineGas = + clampedAdd( + transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L), + gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize())); + final long intrinsicGasCostOrFloor = + Math.max( + gasCalculator.transactionIntrinsicGasCost( + transaction.getPayload(), transaction.isContractCreation(), baselineGas), + gasCalculator.transactionFloorCost(transaction.getPayload())); + + if (Long.compareUnsigned(intrinsicGasCostOrFloor, transaction.getGasLimit()) > 0) { return ValidationResult.invalid( TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, String.format( "intrinsic gas cost %s exceeds gas limit %s", - intrinsicGasCost, transaction.getGasLimit())); + intrinsicGasCostOrFloor, transaction.getGasLimit())); } if (transaction.calculateUpfrontGasCost(transaction.getMaxGasPrice(), Wei.ZERO, 0).bitLength() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index c3b5ef6dc05..432061b61cf 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry; import org.hyperledger.besu.evm.processor.AbstractMessageProcessor; +import org.hyperledger.besu.evm.refundcalculator.RefundCalculator; import java.util.Optional; import java.util.function.BiFunction; @@ -49,6 +50,7 @@ public class ProtocolSpecBuilder { private Supplier gasCalculatorBuilder; + private Supplier refundCalculatorBuilder; private Function gasLimitCalculatorBuilder; private Wei blockReward; private boolean skipZeroBlockRewards; @@ -95,6 +97,12 @@ public ProtocolSpecBuilder gasCalculator(final Supplier gasCalcul return this; } + public ProtocolSpecBuilder refundCalculator( + final Supplier refundCalculatorBuilder) { + this.refundCalculatorBuilder = refundCalculatorBuilder; + return this; + } + public ProtocolSpecBuilder gasLimitCalculatorBuilder( final Function gasLimitCalculatorBuilder) { this.gasLimitCalculatorBuilder = gasLimitCalculatorBuilder; @@ -297,6 +305,7 @@ public ProtocolSpecBuilder isReplayProtectionSupported( public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { checkNotNull(gasCalculatorBuilder, "Missing gasCalculator"); + checkNotNull(refundCalculatorBuilder, "Missing refundCalculator"); checkNotNull(gasLimitCalculatorBuilder, "Missing gasLimitCalculatorBuilder"); checkNotNull(evmBuilder, "Missing operation registry"); checkNotNull(evmConfiguration, "Missing evm configuration"); @@ -324,6 +333,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { checkNotNull(badBlockManager, "Missing bad blocks manager"); final GasCalculator gasCalculator = gasCalculatorBuilder.get(); + final RefundCalculator refundCalculator = refundCalculatorBuilder.get(); final GasLimitCalculator gasLimitCalculator = gasLimitCalculatorBuilder.apply(feeMarket); final EVM evm = evmBuilder.apply(gasCalculator, evmConfiguration); final PrecompiledContractConfiguration precompiledContractConfiguration = @@ -339,6 +349,7 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { final MainnetTransactionProcessor transactionProcessor = transactionProcessorBuilder.apply( gasCalculator, + refundCalculator, feeMarket, transactionValidatorFactory, contractCreationProcessor, @@ -467,6 +478,7 @@ private BlockHeaderValidator createBlockHeaderValidator( public interface TransactionProcessorBuilder { MainnetTransactionProcessor apply( GasCalculator gasCalculator, + RefundCalculator refundCalculator, FeeMarket feeMarket, TransactionValidatorFactory transactionValidatorFactory, AbstractMessageProcessor contractCreationProcessor, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java index bb9ce2b495a..7979cf1338b 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java @@ -16,15 +16,21 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; +import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; +import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; +import java.util.List; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -36,6 +42,8 @@ public class IntrinsicGasTest { public static Stream data() { final GasCalculator frontier = new FrontierGasCalculator(); final GasCalculator istanbul = new IstanbulGasCalculator(); + final GasCalculator shanghai = new ShanghaiGasCalculator(); + final GasCalculator prague = new PragueGasCalculator(); return Stream.of( // EnoughGAS Arguments.of( @@ -81,16 +89,36 @@ public static Stream data() { Arguments.of( istanbul, 21116L, - "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804")); + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // CallData Gas Increase + Arguments.of( + prague, + 21290L, + "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"), + // AccessList + Arguments.of( + shanghai, + 25300L, + "0x01f89a018001826a4094095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f794a95e7baea6a6c7c4c2dfeb977efac326af552d87e1a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a05cbd172231fc0735e0fb994dd5b1a4939170a260b36f0427a8a80866b063b948a07c230f7f578dd61785c93361b9871c0706ebfa6d06e3f4491dc9558c5202ed36")); } @ParameterizedTest @MethodSource("data") public void validateGasCost( final GasCalculator gasCalculator, final long expectedGas, final String txRlp) { - Transaction t = Transaction.readFrom(RLP.input(Bytes.fromHexString(txRlp))); + Bytes rlp = Bytes.fromHexString(txRlp); + + // non-frontier transactions need to be opaque for parsing to work + if (rlp.get(0) > 0) { + final BytesValueRLPOutput output = new BytesValueRLPOutput(); + output.writeBytes(rlp); + rlp = output.encoded(); + } + + Transaction t = Transaction.readFrom(RLP.input(rlp)); Assertions.assertThat( - gasCalculator.transactionIntrinsicGasCost(t.getPayload(), t.isContractCreation())) + gasCalculator.transactionIntrinsicGasCost( + t.getPayload(), t.isContractCreation(), baselineGas(gasCalculator, t))) .isEqualTo(expectedGas); } @@ -100,4 +128,21 @@ void dryRunDetector() { .withFailMessage("This test is here so gradle --dry-run executes this class") .isTrue(); } + + long baselineGas(final GasCalculator gasCalculator, final Transaction transaction) { + final List accessListEntries = transaction.getAccessList().orElse(List.of()); + + int accessListStorageCount = 0; + for (final var entry : accessListEntries) { + final List storageKeys = entry.storageKeys(); + accessListStorageCount += storageKeys.size(); + } + final long accessListGas = + gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); + + final long codeDelegationGas = + gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()); + + return accessListGas + codeDelegationGas; + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index efe0af56652..e8601d97063 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -35,6 +35,8 @@ import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.processor.AbstractMessageProcessor; +import org.hyperledger.besu.evm.refundcalculator.FrontierRefundCalculator; +import org.hyperledger.besu.evm.refundcalculator.RefundCalculator; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldView; @@ -63,6 +65,7 @@ class MainnetTransactionProcessorTest { private static final int MAX_STACK_SIZE = 1024; private final GasCalculator gasCalculator = new LondonGasCalculator(); + private final RefundCalculator refundCalculator = new FrontierRefundCalculator(); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private TransactionValidatorFactory transactionValidatorFactory; @@ -81,6 +84,7 @@ class MainnetTransactionProcessorTest { MainnetTransactionProcessor createTransactionProcessor(final boolean warmCoinbase) { return new MainnetTransactionProcessor( gasCalculator, + refundCalculator, transactionValidatorFactory, contractCreationProcessor, messageCallProcessor, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index c673bf08f68..d663fc4c415 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -128,7 +128,7 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { .gasLimit(10) .chainId(Optional.empty()) .createTransaction(senderKeys); - when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L); + when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L); assertThat( validator.validate( @@ -398,7 +398,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { transaction, Optional.empty(), Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.invalid(INVALID_TRANSACTION_FORMAT)); - when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(0L); + when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(0L); assertThat( eip1559Validator.validate( @@ -475,7 +475,7 @@ public void shouldAcceptValidEIP1559() { .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); final Optional basefee = Optional.of(Wei.of(150000L)); - when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L); + when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L); assertThat( validator.validate(transaction, basefee, Optional.empty(), transactionValidationParams)) @@ -500,7 +500,7 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction .type(TransactionType.EIP1559) .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); - when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L); + when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean(), anyLong())).thenReturn(50L); assertThat( validator.validate( diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 0ff6a21da83..7dde74946a2 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -402,16 +402,20 @@ public void run() { long txGas = gas; if (chargeIntrinsicGas) { - final long intrinsicGasCost = - protocolSpec - .getGasCalculator() - .transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation()); - txGas -= intrinsicGasCost; final long accessListCost = tx.getAccessList() .map(list -> protocolSpec.getGasCalculator().accessListGasCost(list)) .orElse(0L); - txGas -= accessListCost; + + final long delegateCodeCost = + protocolSpec.getGasCalculator().delegateCodeGasCost(tx.codeDelegationListSize()); + + final long intrinsicGasCost = + protocolSpec + .getGasCalculator() + .transactionIntrinsicGasCost( + tx.getPayload(), tx.isContractCreation(), accessListCost + delegateCodeCost); + txGas -= intrinsicGasCost; } final EVM evm = protocolSpec.getEvm(); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 7a5650792fd..75c69ad457c 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -437,7 +437,7 @@ static T8nResult runTest( gasUsed += transactionGasUsed; long intrinsicGas = gasCalculator.transactionIntrinsicGasCost( - transaction.getPayload(), transaction.getTo().isEmpty()); + transaction.getPayload(), transaction.getTo().isEmpty(), 0); TransactionReceipt receipt = protocolSpec .getTransactionReceiptFactory() diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json index f80771a85eb..9747907d5d2 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json @@ -132,9 +132,7 @@ "stdout": { "alloc": { "0x00000000219ab540356cbb839cbe05303d7705fa": { - "balance": "0x3782dace9d9000000", "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033", - "nonce": "0x1", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x85acb6376c2707b118225da41825974c12b5924a05c6a53b988c9cbc33c55b05", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x2f93f18b1befc457f659e486ce25bbe413fe3943ee7634d2afbe83dc512c3d7a", @@ -170,107 +168,109 @@ "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" - } + }, + "balance": "0x3782dace9d9000000", + "nonce": "0x1" }, "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": { - "balance": "0x0", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", - "nonce": "0x1", "storage": { "0x000000000000000000000000000000000000000000000000000000000000000c": "0x000000000000000000000000000000000000000000000000000000000000000c" - } + }, + "balance": "0x0", + "nonce": "0x1" }, "0x00a3ca265ebcb825b45f985a16cefb49958ce017": { - "balance": "0x0", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd", + "balance": "0x0", "nonce": "0x1" }, "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { - "balance": "0x0", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "nonce": "0x1", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xe4fb5d47f70d54b4f36777ea4c882cf767f93d8f8170285d97a1b8275dfe4dbb" - } + }, + "balance": "0x0", + "nonce": "0x1" }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xaa00be18c288efd690", + "balance": "0xaa00be18c288ef24b8", "nonce": "0x2" } }, "body": "0xf90404f901ff8007830f42409400000000219ab540356cbb839cbe05303d7705fa8901bc16d674ec800000b9019422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000011085acb6376c2707b118225da41825974c12b5924a05c6a53b988c9cbc33c55b05000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000325a0ffeb1d6e7ef8e9ee9b64dcdc3b056f9a1d2b94c1572f1949954e712364604575a03d0f42bad795205de84db8d4ab10b9abd0d081ffe560cbf45f6c281768112a69f901ff0107830f42409400000000219ab540356cbb839cbe05303d7705fa8901bc16d674ec800000b9019422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000011085acb6376c2707b118225da41825974c12b5924a05c6a53b988c9cbc33c55b05000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000326a05bb08e348c9c4b0a2e15d04f4a89d1a210d013205de8d3d93e38e5c1b0c8d8aba04300c0f575d9908d2cbc3413ab82895678bb8f3ef356224dd1e7cb972f2c4855", "result": { - "blobGasUsed": "0x0", - "currentBaseFee": "0x7", - "currentDifficulty": null, - "currentExcessBlobGas": "0x0", - "gasUsed": "0x24f10", - "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", + "requestsHash": "0x158ac6beda33cd9341831552555f64c95e074e7024f6c4553c1ed7557077b4c7", + "requests": [ + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030100000000000000", + "0x", + "0x" + ], + "stateRoot": "0xb8aae2dcb0b756c20cbd986f410ba272947fb3a7e15fd9772c5793a326e40db9", + "txRoot": "0x2b790bf82ef7259a0e4513d1b89a77d81e99672ba68758ef2ba3fde32851d023", + "receiptsRoot": "0xd1ec7582334808dc60cddafc5f1ec1bb317252086dafbb983f3becf2be877809", "logsHash": "0x43e31613bfefc1f55d8b3ca2b61f933f3838d523dc11cb5d7ffdd2ecf0ab5d49", + "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", "receipts": [ { - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "contractAddress": "0x0000000000000000000000000000000000000000", - "cumulativeGasUsed": "0x1431e", - "gasUsed": "0x1431e", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x14fd2", + "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", "logs": [ { "address": "0x00000000219ab540356cbb839cbe05303d7705fa", - "blockHash": "0xb7b43f46d6ee34eaaad5ab38807b451e0e85bacbe59893afc625550aa7c65262", - "blockNumber": 1, - "data": "0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080040597307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000", - "logIndex": "0x0", - "removed": "false", "topics": [ "0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5" ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080040597307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 1, "transactionHash": "0x1fe5fcd93d503a72e93ef0a4249e6d9c983cecf33474684f62ece959fc3e8212", - "transactionIndex": "0x0" + "transactionIndex": "0x0", + "blockHash": "0xb7b43f46d6ee34eaaad5ab38807b451e0e85bacbe59893afc625550aa7c65262", + "logIndex": "0x0", + "removed": "false" } ], - "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", - "root": "0x", - "status": "0x1", "transactionHash": "0x1fe5fcd93d503a72e93ef0a4249e6d9c983cecf33474684f62ece959fc3e8212", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x14fd2", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" }, { - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "contractAddress": "0x0000000000000000000000000000000000000000", - "cumulativeGasUsed": "0x24f10", - "gasUsed": "0x10bf2", + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x26878", + "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", "logs": [ { "address": "0x00000000219ab540356cbb839cbe05303d7705fa", - "blockHash": "0xb7b43f46d6ee34eaaad5ab38807b451e0e85bacbe59893afc625550aa7c65262", - "blockNumber": 1, - "data": "0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080040597307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000", - "logIndex": "0x0", - "removed": "false", "topics": [ "0x649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5" ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080040597307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080100000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 1, "transactionHash": "0x3059d7dbc2df8a05442e50ea529419277c2f45582534f452d2d5676d93273c7d", - "transactionIndex": "0x1" + "transactionIndex": "0x1", + "blockHash": "0xb7b43f46d6ee34eaaad5ab38807b451e0e85bacbe59893afc625550aa7c65262", + "logIndex": "0x0", + "removed": "false" } ], - "logsBloom": "0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", - "root": "0x", - "status": "0x1", "transactionHash": "0x3059d7dbc2df8a05442e50ea529419277c2f45582534f452d2d5676d93273c7d", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x118a6", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x1" } ], - "receiptsRoot": "0x9c8d7a917ecb3ff2566f264abbf39131e51b08b07eb2b69cb46989d79d985593", - "requests": [ - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030100000000000000", - "0x", - "0x" - ], - "requestsHash": "0x158ac6beda33cd9341831552555f64c95e074e7024f6c4553c1ed7557077b4c7", - "stateRoot": "0x6471f6d90b87f759176a0ad62a7096f69d0d24fd873bdb6b6ced57d04a71e274", - "txRoot": "0x2b790bf82ef7259a0e4513d1b89a77d81e99672ba68758ef2ba3fde32851d023", - "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + "currentDifficulty": null, + "gasUsed": "0x26878", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "currentExcessBlobGas": "0x0", + "blobGasUsed": "0x0" } } } \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json index 38fd53da0ad..db937770f19 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json @@ -189,14 +189,6 @@ "balance": "0x0", "nonce": "0x1" }, - "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc":{ - "code":"0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "storage":{ - "0x0000000000000000000000000000000000000000000000000000000000000000":"0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb" - }, - "balance":"0x0", - "nonce":"0x1" - }, "0x0c15f14308530b7cdb8460094bbb9cc28b9aaaaa": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "storage": { @@ -206,8 +198,16 @@ "balance": "0x1", "nonce": "0x1" }, + "0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb" + }, + "balance": "0x0", + "nonce": "0x1" + }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xad78ebc5ac61f2b034", + "balance": "0xad78ebc5ac61f2a686", "nonce": "0x1" } }, @@ -219,16 +219,16 @@ "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000", "0x" ], - "stateRoot": "0xc7b49e4aef4229962b94ec0a7c83a6fc0b4015f2573b9a85446ed434c823164e", + "stateRoot": "0xba0d225f94efc13ad895b6654ddc0d328e0b543fae20c072b7d297fdb4725b51", "txRoot": "0x0d36638e52999b7beafa00eb94f7ca23139774cd14229c011d0edc1fc66125c9", - "receiptsRoot": "0x2af83312a6aa55bd8f169e65eec48f92d6d6dc3398bc038d7ccfab5d9aa26b3f", + "receiptsRoot": "0x410435219e22fc9fe2ce684fba034296204c698630962452dbfb9ea5c9369726", "logsHash": "0xac344ad50aad544ec284bf76ac9b939f93e00f8fe16097a151df14bde2065f83", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000", "receipts": [ { "root": "0x", "status": "0x1", - "cumulativeGasUsed": "0x1e6d4", + "cumulativeGasUsed": "0x1e836", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000", "logs": [ { @@ -245,13 +245,13 @@ ], "transactionHash": "0xa888ec4587b7ba70d0127004a96fbb0a83ccb611e61405094e6514b970bf37f6", "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x1e6d4", + "gasUsed": "0x1e836", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } ], "currentDifficulty": null, - "gasUsed": "0x1e6d4", + "gasUsed": "0x1e836", "currentBaseFee": "0x7", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "currentExcessBlobGas": "0x0", diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 5fbab994cf0..49091ad2527 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -207,7 +207,7 @@ dependencies { referenceTestImplementation project(path: ':testutil') referenceTestImplementation project(path: ':util') // the following will be resolved via custom ivy repository declared in root build.gradle - referenceTestImplementation 'ethereum:execution-spec-tests:3.0.0:fixtures_stable@tar.gz' + referenceTestImplementation 'ethereum:execution-spec-tests:pectra-devnet-5@v1.2.0:fixtures_pectra-devnet-5@tar.gz' referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind' referenceTestImplementation 'com.google.guava:guava' referenceTestImplementation 'io.tmio:tuweni-bytes' diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java index e374f5c020f..5d67318ab40 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoOpBonsaiCachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiPreImageProxy; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateLayerStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager; @@ -38,6 +37,8 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.trielogs.TrieLog; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -47,13 +48,18 @@ import com.google.common.cache.CacheBuilder; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BonsaiReferenceTestWorldState extends BonsaiWorldState implements ReferenceTestWorldState { + private static final Logger LOG = LoggerFactory.getLogger(BonsaiReferenceTestWorldState.class); + private final BonsaiReferenceTestWorldStateStorage refTestStorage; private final BonsaiPreImageProxy preImageProxy; private final EvmConfiguration evmConfiguration; + private final Collection exceptionCollector = new ArrayList<>(); protected BonsaiReferenceTestWorldState( final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage, @@ -110,7 +116,8 @@ protected void verifyWorldStateRoot(final Hash calculatedStateRoot, final BlockH } @Override - public void processExtraStateStorageFormatValidation(final BlockHeader blockHeader) { + public Collection processExtraStateStorageFormatValidation( + final BlockHeader blockHeader) { if (blockHeader != null) { final Hash parentStateRoot = getWorldStateRootHash(); final BonsaiReferenceTestUpdateAccumulator originalUpdater = @@ -121,6 +128,7 @@ public void processExtraStateStorageFormatValidation(final BlockHeader blockHead // validate trielog generation with frozen state validateStateRolling(parentStateRoot, originalUpdater, blockHeader, true); } + return exceptionCollector; } /** @@ -156,9 +164,12 @@ private void validateTrieLog( bonsaiWorldState.persist(blockHeader); Hash generatedRootHash = bonsaiWorldState.rootHash(); if (!bonsaiWorldState.rootHash().equals(blockHeader.getStateRoot())) { - throw new RuntimeException( + final String msg = "state root becomes invalid following a rollForward %s != %s" - .formatted(blockHeader.getStateRoot(), generatedRootHash)); + .formatted(blockHeader.getStateRoot(), generatedRootHash); + final RuntimeException e = new RuntimeException(msg); + exceptionCollector.add(e); + LOG.atError().setMessage(msg).setCause(e).log(); } updaterForState = (BonsaiWorldStateUpdateAccumulator) bonsaiWorldState.updater(); @@ -167,9 +178,12 @@ private void validateTrieLog( bonsaiWorldState.persist(null); generatedRootHash = bonsaiWorldState.rootHash(); if (!bonsaiWorldState.rootHash().equals(parentStateRoot)) { - throw new RuntimeException( + final String msg = "state root becomes invalid following a rollBackward %s != %s" - .formatted(parentStateRoot, generatedRootHash)); + .formatted(parentStateRoot, generatedRootHash); + final RuntimeException e = new RuntimeException(msg); + exceptionCollector.add(e); + LOG.atError().setMessage(msg).setCause(e).log(); } } } @@ -189,19 +203,11 @@ private void generateTrieLogFromState( } private BonsaiWorldState createBonsaiWorldState(final boolean isFrozen) { - BonsaiWorldState bonsaiWorldState = - new BonsaiWorldState( - new BonsaiWorldStateLayerStorage( - (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage), - bonsaiCachedMerkleTrieLoader, - cachedWorldStorageManager, - trieLogManager, - evmConfiguration, - new DiffBasedWorldStateConfig()); + final BonsaiReferenceTestWorldState copy = (BonsaiReferenceTestWorldState) this.copy(); if (isFrozen) { - bonsaiWorldState.freeze(); // freeze state + copy.freeze(); } - return bonsaiWorldState; + return copy; } @JsonCreator diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ForestReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ForestReferenceTestWorldState.java index 014e589f696..115c8424892 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ForestReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ForestReferenceTestWorldState.java @@ -24,6 +24,8 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import com.fasterxml.jackson.annotation.JsonCreator; @@ -56,8 +58,10 @@ public ReferenceTestWorldState copy() { * root has been validated, to ensure the integrity of other aspects of the state. */ @Override - public void processExtraStateStorageFormatValidation(final BlockHeader blockHeader) { + public Collection processExtraStateStorageFormatValidation( + final BlockHeader blockHeader) { // nothing more to verify with forest + return Collections.emptyList(); } @JsonCreator diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java index 36b4f8e9376..af9e0ba5c35 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestWorldState.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -91,7 +92,7 @@ static void insertAccount( ReferenceTestWorldState copy(); - void processExtraStateStorageFormatValidation(final BlockHeader blockHeader); + Collection processExtraStateStorageFormatValidation(final BlockHeader blockHeader); @JsonCreator static ReferenceTestWorldState create(final Map accounts) { diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java index a36d3804323..5d1a6078715 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java @@ -75,6 +75,9 @@ public class StateTestVersionedTransaction { // String instead of VersionedHash because reference tests intentionally use bad hashes. private final List blobVersionedHashes; + @JsonDeserialize(contentAs = org.hyperledger.besu.ethereum.core.CodeDelegation.class) + private final List authorizationList; + /** * Constructor for populating a mock transaction with json data. * @@ -103,7 +106,9 @@ public StateTestVersionedTransaction( @JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists") final List> maybeAccessLists, @JsonProperty("maxFeePerBlobGas") final String maxFeePerBlobGas, - @JsonProperty("blobVersionedHashes") final List blobVersionedHashes) { + @JsonProperty("blobVersionedHashes") final List blobVersionedHashes, + @JsonProperty("authorizationList") + final List authorizationList) { this.nonce = Bytes.fromHexStringLenient(nonce).toLong(); this.gasPrice = Optional.ofNullable(gasPrice).map(Wei::fromHexString).orElse(null); @@ -124,6 +129,7 @@ public StateTestVersionedTransaction( this.maxFeePerBlobGas = Optional.ofNullable(maxFeePerBlobGas).map(Wei::fromHexString).orElse(null); this.blobVersionedHashes = blobVersionedHashes; + this.authorizationList = authorizationList; } private static List parseArray(final String[] array, final Function parseFct) { @@ -170,6 +176,7 @@ public Transaction get(final GeneralStateTestCaseSpec.Indexes indexes) { // versioned hash string was bad, so this is an invalid transaction return null; } + Optional.ofNullable(authorizationList).ifPresent(transactionBuilder::codeDelegations); transactionBuilder.guessType(); if (transactionBuilder.getTransactionType().requiresChainId()) { diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java index 9aa04bd0ffe..a3758422c4f 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java @@ -192,10 +192,13 @@ public void milestone( assertThat(transaction.getSender()).isEqualTo(expected.getSender()); assertThat(transaction.getHash()).isEqualTo(expected.getHash()); - final long intrinsicGasCost = - gasCalculator.transactionIntrinsicGasCost( - transaction.getPayload(), transaction.isContractCreation()) - + (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L)); + final long baselineGas = + transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L) + + gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()); + final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost( + transaction.getPayload(), + transaction.isContractCreation(), + baselineGas); assertThat(intrinsicGasCost).isEqualTo(expected.getIntrinsicGas()); } catch (final Exception e) { if (expected.isSucceeds()) { diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java index 7166c13a5b6..60839eaea29 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java @@ -22,6 +22,13 @@ import java.util.Map; import java.util.Optional; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; +import org.assertj.core.api.SoftAssertions; +import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -42,8 +49,12 @@ import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.testutil.JsonTestParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class GeneralStateReferenceTestTools { + private static final Logger LOG = LoggerFactory.getLogger(GeneralStateReferenceTestTools.class); + private static final List SPECS_PRIOR_TO_DELETING_EMPTY_ACCOUNTS = Arrays.asList("Frontier", "Homestead", "EIP150"); @@ -179,16 +190,26 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { worldStateUpdater.deleteAccount(coinbase.getAddress()); } worldStateUpdater.commit(); - worldState.processExtraStateStorageFormatValidation(blockHeader); + Collection additionalExceptions = worldState.processExtraStateStorageFormatValidation(blockHeader); worldState.persist(blockHeader); // Check the world state root hash. final Hash expectedRootHash = spec.getExpectedRootHash(); - assertThat(worldState.rootHash()) - .withFailMessage( - "Unexpected world state root hash; expected state: %s, computed state: %s", - spec.getExpectedRootHash(), worldState.rootHash()) - .isEqualTo(expectedRootHash); + // If the root hash doesn't match, first dump the world state for debugging. + if (!expectedRootHash.equals(worldState.rootHash())) { + logWorldState(worldState); + } + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(worldState.rootHash()) + .withFailMessage( + "Unexpected world state root hash; expected state: %s, computed state: %s", + spec.getExpectedRootHash(), worldState.rootHash()) + .isEqualTo(expectedRootHash); + additionalExceptions.forEach( + e -> softly.fail("Additional exception during state validation: " + e.getMessage())); + + }); // Check the logs. final Hash expectedLogsHash = spec.getExpectedLogsHash(); @@ -206,4 +227,33 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { private static boolean shouldClearEmptyAccounts(final String eip) { return !SPECS_PRIOR_TO_DELETING_EMPTY_ACCOUNTS.contains(eip); } + + private static void logWorldState(final ReferenceTestWorldState worldState) { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode worldStateJson = mapper.createObjectNode(); + worldState.streamAccounts(Bytes32.ZERO, Integer.MAX_VALUE) + .forEach( + account -> { + ObjectNode accountJson = mapper.createObjectNode(); + accountJson.put("nonce", Bytes.ofUnsignedLong(account.getNonce()).toShortHexString()); + accountJson.put("balance", account.getBalance().toShortHexString()); + accountJson.put("code", account.getCode().toHexString()); + ObjectNode storageJson = mapper.createObjectNode(); + var storageEntries = account.storageEntriesFrom(Bytes32.ZERO, Integer.MAX_VALUE); + storageEntries.values().stream() + .map( + e -> + Map.entry( + e.getKey().orElse(UInt256.ZERO), + account.getStorageValue(UInt256.fromBytes(e.getKey().get())))) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> storageJson.put(e.getKey().toQuantityHexString(), e.getValue().toQuantityHexString())); + + if (!storageEntries.isEmpty()) { + accountJson.set("storage", storageJson); + } + worldStateJson.set(account.getAddress().orElse(Address.ZERO).toHexString(), accountJson); + }); + LOG.error("Calculated world state: \n{}", worldStateJson.toPrettyString()); + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java index 0376903c64a..7454fe095aa 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java @@ -38,7 +38,8 @@ public class FrontierGasCalculator implements GasCalculator { private static final long TX_DATA_NON_ZERO_COST = 68L; - private static final long TX_BASE_COST = 21_000L; + /** Minimum base cost that every transaction needs to pay */ + protected static final long TX_BASE_COST = 21_000L; private static final long TX_CREATE_EXTRA_COST = 0L; @@ -128,18 +129,87 @@ public FrontierGasCalculator() { } @Override - public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreate) { + public long transactionIntrinsicGasCost( + final Bytes payload, final boolean isContractCreation, final long baselineGas) { + final long dynamicIntrinsicGasCost = + dynamicIntrinsicGasCost(payload, isContractCreation, baselineGas); + + if (dynamicIntrinsicGasCost == Long.MIN_VALUE || dynamicIntrinsicGasCost == Long.MAX_VALUE) { + return dynamicIntrinsicGasCost; + } + return clampedAdd(TX_BASE_COST, dynamicIntrinsicGasCost); + } + + @Override + public long transactionFloorCost(final Bytes payload) { + return 0; + } + + /** + * Calculates the dynamic part of the intrinsic gas cost + * + * @param payload the call data payload + * @param isContractCreation whether the transaction is a contract creation + * @param baselineGas how much gas is used by access lists and code delegations + * @return the dynamic part of the intrinsic gas cost + */ + protected long dynamicIntrinsicGasCost( + final Bytes payload, final boolean isContractCreation, final long baselineGas) { + final int payloadSize = payload.size(); + final long zeroBytes = zeroBytes(payload); + long cost = clampedAdd(callDataCost(payloadSize, zeroBytes), baselineGas); + + if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) { + return cost; + } + + if (isContractCreation) { + cost = clampedAdd(cost, contractCreationCost(payloadSize)); + + if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) { + return cost; + } + } + + return cost; + } + + /** + * Calculates the cost of the call data + * + * @param payloadSize the total size of the payload + * @param zeroBytes the number of zero bytes in the payload + * @return the cost of the call data + */ + protected long callDataCost(final long payloadSize, final long zeroBytes) { + return clampedAdd( + TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes); + } + + /** + * Counts the zero bytes in the payload + * + * @param payload the payload + * @return the number of zero bytes in the payload + */ + protected static long zeroBytes(final Bytes payload) { int zeros = 0; for (int i = 0; i < payload.size(); i++) { if (payload.get(i) == 0) { - ++zeros; + zeros += 1; } } - final int nonZeros = payload.size() - zeros; - - final long cost = TX_BASE_COST + TX_DATA_ZERO_COST * zeros + TX_DATA_NON_ZERO_COST * nonZeros; + return zeros; + } - return isContractCreate ? (cost + txCreateExtraGasCost()) : cost; + /** + * Returns the gas cost for contract creation transactions + * + * @param ignored the size of the contract creation code (ignored in Frontier) + * @return the gas cost for contract creation transactions + */ + protected long contractCreationCost(final int ignored) { + return txCreateExtraGasCost(); } /** @@ -557,11 +627,6 @@ static long memoryCost(final long length) { return clampedAdd(clampedMultiply(MEMORY_WORD_GAS_COST, length), base); } - @Override - public long getMaximumTransactionCost(final int size) { - return TX_BASE_COST + TX_DATA_NON_ZERO_COST * size; - } - @Override public long getMinimumTransactionCost() { return TX_BASE_COST; diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 8192bd1af88..51d2767995e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -542,10 +542,21 @@ default long modExpGasCost(final Bytes input) { * encoded binary representation when stored on-chain. * * @param transactionPayload The encoded transaction, as bytes - * @param isContractCreate Is this transaction a contract creation transaction? + * @param isContractCreation Is this transaction a contract creation transaction? + * @param baselineGas The gas used by access lists and code delegation authorizations * @return the transaction's intrinsic gas cost */ - long transactionIntrinsicGasCost(Bytes transactionPayload, boolean isContractCreate); + long transactionIntrinsicGasCost( + Bytes transactionPayload, boolean isContractCreation, long baselineGas); + + /** + * Returns the floor gas cost of a transaction payload, i.e. the minimum gas cost that a + * transaction will be charged based on its calldata. Introduced in EIP-7623 in Prague. + * + * @param transactionPayload The encoded transaction, as bytes + * @return the transaction's floor gas cost + */ + long transactionFloorCost(final Bytes transactionPayload); /** * Returns the gas cost of the explicitly declared access list. @@ -579,15 +590,6 @@ default long getMaxRefundQuotient() { return 2; } - /** - * Maximum Cost of a Transaction of a certain length. - * - * @param size the length of the transaction, in bytes - * @return the maximum gas cost - */ - // what would be the gas for a PMT with hash of all non-zeros - long getMaximumTransactionCost(int size); - /** * Minimum gas cost of a transaction. * diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/IstanbulGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/IstanbulGasCalculator.java index a997f7fe16e..5df0c168bd3 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/IstanbulGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/IstanbulGasCalculator.java @@ -14,9 +14,10 @@ */ package org.hyperledger.besu.evm.gascalculator; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; + import java.util.function.Supplier; -import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; /** The Istanbul gas calculator. */ @@ -24,7 +25,6 @@ public class IstanbulGasCalculator extends PetersburgGasCalculator { private static final long TX_DATA_ZERO_COST = 4L; private static final long ISTANBUL_TX_DATA_NON_ZERO_COST = 16L; - private static final long TX_BASE_COST = 21_000L; private static final long SLOAD_GAS = 800L; private static final long BALANCE_OPERATION_GAS_COST = 700L; @@ -42,19 +42,9 @@ public class IstanbulGasCalculator extends PetersburgGasCalculator { public IstanbulGasCalculator() {} @Override - public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) { - int zeros = 0; - for (int i = 0; i < payload.size(); i++) { - if (payload.get(i) == 0) { - ++zeros; - } - } - final int nonZeros = payload.size() - zeros; - - final long cost = - TX_BASE_COST + (TX_DATA_ZERO_COST * zeros) + (ISTANBUL_TX_DATA_NON_ZERO_COST * nonZeros); - - return isContractCreation ? (cost + txCreateExtraGasCost()) : cost; + protected long callDataCost(final long payloadSize, final long zeroBytes) { + return clampedAdd( + ISTANBUL_TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes); } @Override @@ -136,9 +126,4 @@ public long getBalanceOperationGasCost() { public long extCodeHashOperationGasCost() { return EXTCODE_HASH_COST; } - - @Override - public long getMaximumTransactionCost(final int size) { - return TX_BASE_COST + (ISTANBUL_TX_DATA_NON_ZERO_COST * size); - } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java index 268a58061c7..350247405ae 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java @@ -15,9 +15,12 @@ package org.hyperledger.besu.evm.gascalculator; import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; +import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import org.hyperledger.besu.datatypes.CodeDelegation; +import org.apache.tuweni.bytes.Bytes; + /** * Gas Calculator for Prague * @@ -26,6 +29,8 @@ * */ public class PragueGasCalculator extends CancunGasCalculator { + private static final long TOTAL_COST_FLOOR_PER_TOKEN = 10L; + final long existingAccountGasRefund; /** @@ -68,4 +73,24 @@ public long delegateCodeGasCost(final int delegateCodeListLength) { public long calculateDelegateCodeGasRefund(final long alreadyExistingAccounts) { return existingAccountGasRefund * alreadyExistingAccounts; } + + @Override + public long transactionIntrinsicGasCost( + final Bytes payload, final boolean isContractCreation, final long baselineGas) { + return clampedAdd( + TX_BASE_COST, dynamicIntrinsicGasCost(payload, isContractCreation, baselineGas)); + } + + @Override + public long transactionFloorCost(final Bytes transactionPayload) { + return clampedAdd( + TX_BASE_COST, + tokensInCallData(transactionPayload.size(), zeroBytes(transactionPayload)) + * TOTAL_COST_FLOOR_PER_TOKEN); + } + + private long tokensInCallData(final long payloadSize, final long zeroBytes) { + // as defined in https://eips.ethereum.org/EIPS/eip-7623#specification + return clampedAdd(zeroBytes, (payloadSize - zeroBytes) * 4); + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java index a44300f06a3..aa0dd080dd6 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ShanghaiGasCalculator.java @@ -14,11 +14,8 @@ */ package org.hyperledger.besu.evm.gascalculator; -import static org.hyperledger.besu.evm.internal.Words.clampedAdd; import static org.hyperledger.besu.evm.internal.Words.numWords; -import org.apache.tuweni.bytes.Bytes; - /** The Shanghai gas calculator. */ public class ShanghaiGasCalculator extends LondonGasCalculator { @@ -39,13 +36,8 @@ public ShanghaiGasCalculator() { } @Override - public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) { - long intrinsicGasCost = super.transactionIntrinsicGasCost(payload, isContractCreation); - if (isContractCreation) { - return clampedAdd(intrinsicGasCost, initcodeCost(payload.size())); - } else { - return intrinsicGasCost; - } + protected long contractCreationCost(final int initCodeLength) { + return txCreateExtraGasCost() + initcodeCost(initCodeLength); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculator.java new file mode 100644 index 00000000000..489d28bb5a2 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculator.java @@ -0,0 +1,66 @@ +/* + * 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 + */ +package org.hyperledger.besu.evm.refundcalculator; + +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +/** Refund calculator for the Frontier hard fork. */ +public class FrontierRefundCalculator implements RefundCalculator { + + /** Instantiates a new Frontier refund calculator. */ + public FrontierRefundCalculator() { + // empty + } + + @Override + public long calculateGasRefund( + final GasCalculator gasCalculator, + final Transaction transaction, + final MessageFrame initialFrame, + final long codeDelegationRefund) { + + final long refundAllowance = + calculateRefundAllowance(gasCalculator, transaction, initialFrame, codeDelegationRefund); + + return initialFrame.getRemainingGas() + refundAllowance; + } + + /** + * Calculate the refund allowance for a transaction. + * + * @param gasCalculator the gas calculator + * @param transaction the transaction + * @param initialFrame the initial frame + * @param codeDelegationRefund the code delegation refund + * @return the refund allowance + */ + protected long calculateRefundAllowance( + final GasCalculator gasCalculator, + final Transaction transaction, + final MessageFrame initialFrame, + final long codeDelegationRefund) { + final long selfDestructRefund = + gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size(); + final long baseRefundGas = + initialFrame.getGasRefund() + selfDestructRefund + codeDelegationRefund; + // Integer truncation takes care of the floor calculation needed after the divide. + final long maxRefundAllowance = + (transaction.getGasLimit() - initialFrame.getRemainingGas()) + / gasCalculator.getMaxRefundQuotient(); + return Math.min(maxRefundAllowance, baseRefundGas); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/PragueRefundCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/PragueRefundCalculator.java new file mode 100644 index 00000000000..9122e9f32d6 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/PragueRefundCalculator.java @@ -0,0 +1,44 @@ +/* + * 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 + */ +package org.hyperledger.besu.evm.refundcalculator; + +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +/** Refund calculator for the Prague hard fork. */ +public class PragueRefundCalculator extends FrontierRefundCalculator implements RefundCalculator { + + /** Instantiates a new Prague refund calculator. */ + public PragueRefundCalculator() { + // empty + } + + @Override + public long calculateGasRefund( + final GasCalculator gasCalculator, + final Transaction transaction, + final MessageFrame initialFrame, + final long codeDelegationRefund) { + final long refundAllowance = + calculateRefundAllowance(gasCalculator, transaction, initialFrame, codeDelegationRefund); + + final long executionGasUsed = + transaction.getGasLimit() - initialFrame.getRemainingGas() - refundAllowance; + final long transactionFloorCost = gasCalculator.transactionFloorCost(transaction.getPayload()); + final long totalGasUsed = Math.max(executionGasUsed, transactionFloorCost); + return transaction.getGasLimit() - totalGasUsed; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/RefundCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/RefundCalculator.java new file mode 100644 index 00000000000..ef6ff9473a2 --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/refundcalculator/RefundCalculator.java @@ -0,0 +1,37 @@ +/* + * 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 + */ +package org.hyperledger.besu.evm.refundcalculator; + +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +/** Refund calculator, which calculates how much gas is refunded at the end of a transaction */ +public interface RefundCalculator { + /** + * Calculate the gas refund for a transaction. + * + * @param gasCalculator the gas calculator + * @param transaction the transaction + * @param initialFrame the initial frame + * @param codeDelegationRefund the code delegation refund + * @return the gas refund + */ + long calculateGasRefund( + GasCalculator gasCalculator, + Transaction transaction, + MessageFrame initialFrame, + long codeDelegationRefund); +} diff --git a/evm/src/test/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculatorTest.java new file mode 100644 index 00000000000..052f1e1a220 --- /dev/null +++ b/evm/src/test/java/org/hyperledger/besu/evm/refundcalculator/FrontierRefundCalculatorTest.java @@ -0,0 +1,112 @@ +/* + * 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 + */ +package org.hyperledger.besu.evm.refundcalculator; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.evm.frame.MessageFrame; +import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class FrontierRefundCalculatorTest { + private final FrontierRefundCalculator refundCalculator = new FrontierRefundCalculator(); + private final GasCalculator gasCalculator = new FrontierGasCalculator(); + @Mock private Transaction transaction; + @Mock private MessageFrame messageFrame; + + @Test + void shouldCalculateRefundWithNoSelfDestructs() { + // Arrange + when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet()); + when(messageFrame.getGasRefund()).thenReturn(1000L); + when(messageFrame.getRemainingGas()).thenReturn(5000L); + when(transaction.getGasLimit()).thenReturn(100000L); + + // Act + long refund = + refundCalculator.calculateGasRefund(gasCalculator, transaction, messageFrame, 500L); + + // Assert + assertThat(refund) + .isEqualTo(6500L); // 5000 (remaining) + min(1500 (total refund), 19000 (max allowance)) + } + + @Test + void shouldCalculateRefundWithMultipleSelfDestructs() { + // Arrange + Set
selfDestructs = new HashSet<>(); + selfDestructs.add(Address.wrap(Bytes.random(20))); + selfDestructs.add(Address.wrap(Bytes.random(20))); + + when(messageFrame.getSelfDestructs()).thenReturn(selfDestructs); + when(messageFrame.getGasRefund()).thenReturn(1000L); + when(messageFrame.getRemainingGas()).thenReturn(5000L); + when(transaction.getGasLimit()).thenReturn(100000L); + + // Act + long refund = + refundCalculator.calculateGasRefund(gasCalculator, transaction, messageFrame, 500L); + + // Assert + assertThat(refund) + .isEqualTo(52500L); // 5000 (remaining) + min(47500 (total refund), 49500 (max allowance)) + } + + @Test + void shouldRespectMaxRefundAllowance() { + // Arrange + when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet()); + when(messageFrame.getGasRefund()).thenReturn(100000L); + when(messageFrame.getRemainingGas()).thenReturn(20000L); + when(transaction.getGasLimit()).thenReturn(100000L); + + // Act + long refund = + refundCalculator.calculateGasRefund(gasCalculator, transaction, messageFrame, 1000L); + + // Assert + assertThat(refund) + .isEqualTo(60000L); // 20000 (remaining) + min(101000 (total refund), 40000 (max allowance)) + } + + @Test + void shouldHandleZeroValuesCorrectly() { + // Arrange + when(messageFrame.getSelfDestructs()).thenReturn(Collections.emptySet()); + when(messageFrame.getGasRefund()).thenReturn(0L); + when(messageFrame.getRemainingGas()).thenReturn(0L); + when(transaction.getGasLimit()).thenReturn(100000L); + + // Act + long refund = refundCalculator.calculateGasRefund(gasCalculator, transaction, messageFrame, 0L); + + // Assert + assertThat(refund).isEqualTo(0L); + } +} diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 42b3d5d5662..2da235d3f4a 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1589,6 +1589,11 @@ + + + + +