mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 13:58:02 -05:00
Merge branch 'main' into zkbesu
# Conflicts: # .github/pull_request_template.md # .github/workflows/sonarcloud.yml
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -4,11 +4,17 @@
|
|||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
### Upcoming Breaking Changes
|
### Upcoming Breaking Changes
|
||||||
### Additions and Improvements
|
### Additions and Improvements
|
||||||
- Adds timestamps to enable Prague hardfork on Sepolia and Holesky test networks. [#8163](https://github.com/hyperledger/besu/pull/8163)
|
- Add a tx selector to skip txs from the same sender after the first not selected [#8216](https://github.com/hyperledger/besu/pull/8216)
|
||||||
|
|
||||||
|
#### Prague
|
||||||
|
- Add timestamps to enable Prague hardfork on Sepolia and Holesky test networks [#8163](https://github.com/hyperledger/besu/pull/8163)
|
||||||
|
- Update system call addresses to match [devnet-6](https://github.com/ethereum/execution-spec-tests/releases/) values [#8209](https://github.com/hyperledger/besu/issues/8209)
|
||||||
|
|
||||||
|
#### Plugins
|
||||||
- Extend simulate transaction on pending block plugin API [#8174](https://github.com/hyperledger/besu/pull/8174)
|
- Extend simulate transaction on pending block plugin API [#8174](https://github.com/hyperledger/besu/pull/8174)
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
- Fix the simulation of txs with a future nonce [#8215](https://github.com/hyperledger/besu/pull/8215)
|
||||||
|
|
||||||
## 25.1.0
|
## 25.1.0
|
||||||
|
|
||||||
|
|||||||
@@ -532,6 +532,7 @@ public class BesuNodeFactory {
|
|||||||
.jsonRpcTxPool()
|
.jsonRpcTxPool()
|
||||||
.engineRpcEnabled(true)
|
.engineRpcEnabled(true)
|
||||||
.jsonRpcDebug()
|
.jsonRpcDebug()
|
||||||
|
.dataStorageConfiguration(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.tests.acceptance.dsl.transaction.eth;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.web3j.protocol.core.DefaultBlockParameterName.LATEST;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
|
||||||
|
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
|
import org.web3j.protocol.core.methods.response.EthGetCode;
|
||||||
|
|
||||||
|
public class EthGetCodeTransaction implements Transaction<Bytes> {
|
||||||
|
|
||||||
|
private final Account account;
|
||||||
|
|
||||||
|
public EthGetCodeTransaction(final Account account) {
|
||||||
|
this.account = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bytes execute(final NodeRequests node) {
|
||||||
|
try {
|
||||||
|
final EthGetCode result = node.eth().ethGetCode(account.getAddress(), LATEST).send();
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.hasError()).isFalse();
|
||||||
|
|
||||||
|
return Bytes.fromHexString(result.getCode());
|
||||||
|
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,6 +43,10 @@ public class EthTransactions {
|
|||||||
return new EthGetBalanceTransaction(account);
|
return new EthGetBalanceTransaction(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EthGetCodeTransaction getCode(final Account account) {
|
||||||
|
return new EthGetCodeTransaction(account);
|
||||||
|
}
|
||||||
|
|
||||||
public EthGetBalanceAtBlockTransaction getBalanceAtBlock(
|
public EthGetBalanceAtBlockTransaction getBalanceAtBlock(
|
||||||
final Account account, final BigInteger block) {
|
final Account account, final BigInteger block) {
|
||||||
return new EthGetBalanceAtBlockTransaction(account, block);
|
return new EthGetBalanceAtBlockTransaction(account, block);
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
|
|||||||
public static final Address SEND_ALL_ETH_CONTRACT_ADDRESS =
|
public static final Address SEND_ALL_ETH_CONTRACT_ADDRESS =
|
||||||
Address.fromHexStringStrict("0000000000000000000000000000000000009999");
|
Address.fromHexStringStrict("0000000000000000000000000000000000009999");
|
||||||
|
|
||||||
|
public static final Address ALWAYS_REVERT_CONTRACT_ADDRESS =
|
||||||
|
Address.fromHexStringStrict("0000000000000000000000000000000000000666");
|
||||||
|
|
||||||
private final Account authorizer =
|
private final Account authorizer =
|
||||||
accounts.createAccount(
|
accounts.createAccount(
|
||||||
Address.fromHexStringStrict("8da48afC965480220a3dB9244771bd3afcB5d895"));
|
Address.fromHexStringStrict("8da48afC965480220a3dB9244771bd3afcB5d895"));
|
||||||
@@ -232,4 +235,124 @@ public class CodeDelegationTransactionAcceptanceTest extends AcceptanceTestBase
|
|||||||
assertThat(otherAccountBalanceAfterFirstTx.add(BigInteger.ONE))
|
assertThat(otherAccountBalanceAfterFirstTx.add(BigInteger.ONE))
|
||||||
.isEqualTo(otherAccountBalanceAfterSecondTx);
|
.isEqualTo(otherAccountBalanceAfterSecondTx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EIP-7702 code delegation should be persisted even if the transaction that contains the
|
||||||
|
* authorization is reverted.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldPersistCodeDelegationAfterRevert() throws IOException {
|
||||||
|
final long GAS_LIMIT = 1_000_000L;
|
||||||
|
|
||||||
|
// check the authorizer has no code before the transaction
|
||||||
|
final Bytes authorizerCodeBeforeCodeDelegation =
|
||||||
|
besuNode.execute(ethTransactions.getCode(authorizer));
|
||||||
|
assertThat(authorizerCodeBeforeCodeDelegation).isEqualTo(Bytes.EMPTY);
|
||||||
|
|
||||||
|
// valid 7702 code delegation to SEND_ALL_ETH_CONTRACT_ADDRESS
|
||||||
|
final CodeDelegation codeDelegation =
|
||||||
|
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
|
||||||
|
.chainId(BigInteger.valueOf(20211))
|
||||||
|
.nonce(0L)
|
||||||
|
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
|
||||||
|
.signAndBuild(
|
||||||
|
secp256k1.createKeyPair(
|
||||||
|
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
|
||||||
|
|
||||||
|
// the transaction will revert, because the to address is a contract that always reverts
|
||||||
|
final Transaction tx =
|
||||||
|
Transaction.builder()
|
||||||
|
.type(TransactionType.DELEGATE_CODE)
|
||||||
|
.chainId(BigInteger.valueOf(20211))
|
||||||
|
.nonce(0)
|
||||||
|
.maxPriorityFeePerGas(Wei.of(1_000_000_000))
|
||||||
|
.maxFeePerGas(Wei.fromHexString("0x02540BE400"))
|
||||||
|
.gasLimit(GAS_LIMIT)
|
||||||
|
.to(ALWAYS_REVERT_CONTRACT_ADDRESS)
|
||||||
|
.value(Wei.ZERO)
|
||||||
|
.payload(Bytes.EMPTY)
|
||||||
|
.codeDelegations(List.of(codeDelegation))
|
||||||
|
.signAndBuild(
|
||||||
|
secp256k1.createKeyPair(
|
||||||
|
secp256k1.createPrivateKey(
|
||||||
|
TRANSACTION_SPONSOR_PRIVATE_KEY.toUnsignedBigInteger())));
|
||||||
|
|
||||||
|
// include the tx in the next block
|
||||||
|
final String txHash =
|
||||||
|
besuNode.execute(ethTransactions.sendRawTransaction(tx.encoded().toHexString()));
|
||||||
|
testHelper.buildNewBlock();
|
||||||
|
|
||||||
|
// check that the transaction was included and has indeed reverted
|
||||||
|
Optional<TransactionReceipt> maybeTransactionReceipt =
|
||||||
|
besuNode.execute(ethTransactions.getTransactionReceipt(txHash));
|
||||||
|
assertThat(maybeTransactionReceipt).isPresent();
|
||||||
|
assertThat(maybeTransactionReceipt.get().getStatus()).isEqualTo("0x0");
|
||||||
|
|
||||||
|
// check the authorizer has the code delegation after the transaction even though it has
|
||||||
|
// reverted
|
||||||
|
final Bytes expectedCode =
|
||||||
|
Bytes.concatenate(Bytes.fromHexString("ef0100"), SEND_ALL_ETH_CONTRACT_ADDRESS);
|
||||||
|
final Bytes authorizerCode = besuNode.execute(ethTransactions.getCode(authorizer));
|
||||||
|
assertThat(authorizerCode).isEqualTo(expectedCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EIP-7702 code delegation should be persisted even if the transaction that contains the
|
||||||
|
* authorization is reverted and the transaction sender is the same as the code delegation
|
||||||
|
* authorizer.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldPersistCodeDelegationAfterRevertWhenSelfSponsored() throws IOException {
|
||||||
|
final long GAS_LIMIT = 1_000_000L;
|
||||||
|
|
||||||
|
// check the authorizer has no code before the transaction
|
||||||
|
final Bytes authorizerCodeBeforeCodeDelegation =
|
||||||
|
besuNode.execute(ethTransactions.getCode(authorizer));
|
||||||
|
assertThat(authorizerCodeBeforeCodeDelegation).isEqualTo(Bytes.EMPTY);
|
||||||
|
|
||||||
|
// valid 7702 code delegation to SEND_ALL_ETH_CONTRACT_ADDRESS
|
||||||
|
final CodeDelegation codeDelegation =
|
||||||
|
org.hyperledger.besu.ethereum.core.CodeDelegation.builder()
|
||||||
|
.chainId(BigInteger.valueOf(20211))
|
||||||
|
.nonce(1L)
|
||||||
|
.address(SEND_ALL_ETH_CONTRACT_ADDRESS)
|
||||||
|
.signAndBuild(
|
||||||
|
secp256k1.createKeyPair(
|
||||||
|
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
|
||||||
|
|
||||||
|
// the transaction will revert, because the to address is a contract that always reverts
|
||||||
|
final Transaction tx =
|
||||||
|
Transaction.builder()
|
||||||
|
.type(TransactionType.DELEGATE_CODE)
|
||||||
|
.chainId(BigInteger.valueOf(20211))
|
||||||
|
.nonce(0)
|
||||||
|
.maxPriorityFeePerGas(Wei.of(1_000_000_000))
|
||||||
|
.maxFeePerGas(Wei.fromHexString("0x02540BE400"))
|
||||||
|
.gasLimit(GAS_LIMIT)
|
||||||
|
.to(ALWAYS_REVERT_CONTRACT_ADDRESS)
|
||||||
|
.value(Wei.ZERO)
|
||||||
|
.payload(Bytes.EMPTY)
|
||||||
|
.codeDelegations(List.of(codeDelegation))
|
||||||
|
.signAndBuild(
|
||||||
|
secp256k1.createKeyPair(
|
||||||
|
secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger())));
|
||||||
|
|
||||||
|
// include the tx in the next block
|
||||||
|
final String txHash =
|
||||||
|
besuNode.execute(ethTransactions.sendRawTransaction(tx.encoded().toHexString()));
|
||||||
|
testHelper.buildNewBlock();
|
||||||
|
|
||||||
|
// check that the transaction was included and has indeed reverted
|
||||||
|
Optional<TransactionReceipt> maybeTransactionReceipt =
|
||||||
|
besuNode.execute(ethTransactions.getTransactionReceipt(txHash));
|
||||||
|
assertThat(maybeTransactionReceipt).isPresent();
|
||||||
|
assertThat(maybeTransactionReceipt.get().getStatus()).isEqualTo("0x0");
|
||||||
|
|
||||||
|
// check the authorizer has the code delegation after the transaction even though it has
|
||||||
|
// reverted
|
||||||
|
final Bytes expectedCode =
|
||||||
|
Bytes.concatenate(Bytes.fromHexString("ef0100"), SEND_ALL_ETH_CONTRACT_ADDRESS);
|
||||||
|
final Bytes authorizerCode = besuNode.execute(ethTransactions.getCode(authorizer));
|
||||||
|
assertThat(authorizerCode).isEqualTo(expectedCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,13 @@
|
|||||||
"privateKey": "11f2e7b6a734ab03fa682450e0d4681d18a944f8b83c99bf7b9b4de6c0f35ea1",
|
"privateKey": "11f2e7b6a734ab03fa682450e0d4681d18a944f8b83c99bf7b9b4de6c0f35ea1",
|
||||||
"balance": "90000000000000000000000"
|
"balance": "90000000000000000000000"
|
||||||
},
|
},
|
||||||
|
"0x0000000000000000000000000000000000000666": {
|
||||||
|
"comment": "Contract reverts immediately when called",
|
||||||
|
"balance": "0",
|
||||||
|
"code": "5F5FFD",
|
||||||
|
"codeDecompiled": "PUSH0 PUSH0 REVERT",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
"0x0000000000000000000000000000000000009999": {
|
"0x0000000000000000000000000000000000009999": {
|
||||||
"comment": "Contract sends all its Ether to the address provided as a call data.",
|
"comment": "Contract sends all its Ether to the address provided as a call data.",
|
||||||
"balance": "0",
|
"balance": "0",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -69,6 +69,7 @@ import org.hyperledger.besu.cli.options.SynchronizerOptions;
|
|||||||
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
|
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
|
||||||
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
|
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
|
||||||
import org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions;
|
import org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions;
|
||||||
|
import org.hyperledger.besu.cli.options.unstable.QBFTOptions;
|
||||||
import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner;
|
import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner;
|
||||||
import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask;
|
import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask;
|
||||||
import org.hyperledger.besu.cli.subcommands.PasswordSubCommand;
|
import org.hyperledger.besu.cli.subcommands.PasswordSubCommand;
|
||||||
@@ -301,6 +302,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
|||||||
private final EvmOptions unstableEvmOptions = EvmOptions.create();
|
private final EvmOptions unstableEvmOptions = EvmOptions.create();
|
||||||
private final IpcOptions unstableIpcOptions = IpcOptions.create();
|
private final IpcOptions unstableIpcOptions = IpcOptions.create();
|
||||||
private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create();
|
private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create();
|
||||||
|
private final QBFTOptions unstableQbftOptions = QBFTOptions.create();
|
||||||
|
|
||||||
// stable CLI options
|
// stable CLI options
|
||||||
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
|
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
|
||||||
@@ -1162,6 +1164,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
|||||||
.put("EVM Options", unstableEvmOptions)
|
.put("EVM Options", unstableEvmOptions)
|
||||||
.put("IPC Options", unstableIpcOptions)
|
.put("IPC Options", unstableIpcOptions)
|
||||||
.put("Chain Data Pruning Options", unstableChainPruningOptions)
|
.put("Chain Data Pruning Options", unstableChainPruningOptions)
|
||||||
|
.put("QBFT Options", unstableQbftOptions)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions);
|
UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions);
|
||||||
@@ -1794,6 +1797,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
|||||||
.clock(Clock.systemUTC())
|
.clock(Clock.systemUTC())
|
||||||
.isRevertReasonEnabled(isRevertReasonEnabled)
|
.isRevertReasonEnabled(isRevertReasonEnabled)
|
||||||
.storageProvider(storageProvider)
|
.storageProvider(storageProvider)
|
||||||
|
.isEarlyRoundChangeEnabled(unstableQbftOptions.isEarlyRoundChangeEnabled())
|
||||||
.gasLimitCalculator(
|
.gasLimitCalculator(
|
||||||
miningParametersSupplier.get().getTargetGasLimit().isPresent()
|
miningParametersSupplier.get().getTargetGasLimit().isPresent()
|
||||||
? new FrontierTargetingGasLimitCalculator()
|
? new FrontierTargetingGasLimitCalculator()
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright contributors to 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.cli.options.unstable;
|
||||||
|
|
||||||
|
import picocli.CommandLine;
|
||||||
|
|
||||||
|
/** Handles configuration options for QBFT consensus */
|
||||||
|
public class QBFTOptions {
|
||||||
|
|
||||||
|
/** Default constructor */
|
||||||
|
private QBFTOptions() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of QBFTOptions
|
||||||
|
*
|
||||||
|
* @return a new instance of QBFTOptions
|
||||||
|
*/
|
||||||
|
public static QBFTOptions create() {
|
||||||
|
return new QBFTOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = {"--Xqbft-enable-early-round-change"},
|
||||||
|
description =
|
||||||
|
"Enable early round change upon receiving f+1 valid future Round Change messages from different validators (experimental)",
|
||||||
|
hidden = true)
|
||||||
|
private boolean enableEarlyRoundChange = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is early round change enabled boolean.
|
||||||
|
*
|
||||||
|
* @return true if early round change is enabled
|
||||||
|
*/
|
||||||
|
public boolean isEarlyRoundChangeEnabled() {
|
||||||
|
return enableEarlyRoundChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
|
|||||||
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
|
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
|
||||||
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
|
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
|
||||||
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
||||||
|
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
|
||||||
import org.hyperledger.besu.metrics.MetricsService;
|
import org.hyperledger.besu.metrics.MetricsService;
|
||||||
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
|
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
|
||||||
|
|
||||||
@@ -206,6 +207,7 @@ public class BlocksSubCommand implements Runnable {
|
|||||||
}
|
}
|
||||||
LOG.info("Import {} block data from {} files", format, blockImportFiles.size());
|
LOG.info("Import {} block data from {} files", format, blockImportFiles.size());
|
||||||
final Optional<MetricsService> metricsService = initMetrics(parentCommand);
|
final Optional<MetricsService> metricsService = initMetrics(parentCommand);
|
||||||
|
KZGPointEvalPrecompiledContract.init();
|
||||||
|
|
||||||
try (final BesuController controller = createController()) {
|
try (final BesuController controller = createController()) {
|
||||||
for (final Path path : blockImportFiles) {
|
for (final Path path : blockImportFiles) {
|
||||||
|
|||||||
@@ -219,6 +219,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
|
|||||||
/** The transaction simulator */
|
/** The transaction simulator */
|
||||||
protected TransactionSimulator transactionSimulator;
|
protected TransactionSimulator transactionSimulator;
|
||||||
|
|
||||||
|
/** When enabled, round changes on f+1 RC messages from higher rounds */
|
||||||
|
protected boolean isEarlyRoundChangeEnabled = false;
|
||||||
|
|
||||||
/** Instantiates a new Besu controller builder. */
|
/** Instantiates a new Besu controller builder. */
|
||||||
protected BesuControllerBuilder() {}
|
protected BesuControllerBuilder() {}
|
||||||
|
|
||||||
@@ -553,6 +556,17 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if early round change is enabled when f+1 RC messages from higher rounds are received
|
||||||
|
*
|
||||||
|
* @param isEarlyRoundChangeEnabled whether to enable early round change
|
||||||
|
* @return the besu controller
|
||||||
|
*/
|
||||||
|
public BesuControllerBuilder isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) {
|
||||||
|
this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build besu controller.
|
* Build besu controller.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -245,23 +245,28 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
|
|||||||
|
|
||||||
final MessageFactory messageFactory = new MessageFactory(nodeKey);
|
final MessageFactory messageFactory = new MessageFactory(nodeKey);
|
||||||
|
|
||||||
|
QbftBlockHeightManagerFactory qbftBlockHeightManagerFactory =
|
||||||
|
new QbftBlockHeightManagerFactory(
|
||||||
|
finalState,
|
||||||
|
new QbftRoundFactory(
|
||||||
|
finalState,
|
||||||
|
protocolContext,
|
||||||
|
bftProtocolSchedule,
|
||||||
|
minedBlockObservers,
|
||||||
|
messageValidatorFactory,
|
||||||
|
messageFactory,
|
||||||
|
bftExtraDataCodec().get()),
|
||||||
|
messageValidatorFactory,
|
||||||
|
messageFactory,
|
||||||
|
new ValidatorModeTransitionLogger(qbftForksSchedule));
|
||||||
|
|
||||||
|
qbftBlockHeightManagerFactory.isEarlyRoundChangeEnabled(isEarlyRoundChangeEnabled);
|
||||||
|
|
||||||
final BftEventHandler qbftController =
|
final BftEventHandler qbftController =
|
||||||
new QbftController(
|
new QbftController(
|
||||||
blockchain,
|
blockchain,
|
||||||
finalState,
|
finalState,
|
||||||
new QbftBlockHeightManagerFactory(
|
qbftBlockHeightManagerFactory,
|
||||||
finalState,
|
|
||||||
new QbftRoundFactory(
|
|
||||||
finalState,
|
|
||||||
protocolContext,
|
|
||||||
bftProtocolSchedule,
|
|
||||||
minedBlockObservers,
|
|
||||||
messageValidatorFactory,
|
|
||||||
messageFactory,
|
|
||||||
bftExtraDataCodec().get()),
|
|
||||||
messageValidatorFactory,
|
|
||||||
messageFactory,
|
|
||||||
new ValidatorModeTransitionLogger(qbftForksSchedule)),
|
|
||||||
gossiper,
|
gossiper,
|
||||||
duplicateMessageTracker,
|
duplicateMessageTracker,
|
||||||
futureMessageBuffer,
|
futureMessageBuffer,
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ public abstract class CommandTestAbstract {
|
|||||||
when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder);
|
when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder);
|
||||||
when(mockControllerBuilder.isParallelTxProcessingEnabled(false))
|
when(mockControllerBuilder.isParallelTxProcessingEnabled(false))
|
||||||
.thenReturn(mockControllerBuilder);
|
.thenReturn(mockControllerBuilder);
|
||||||
|
when(mockControllerBuilder.isEarlyRoundChangeEnabled(false)).thenReturn(mockControllerBuilder);
|
||||||
when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder);
|
when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder);
|
||||||
when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder);
|
when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder);
|
||||||
when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder);
|
when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder);
|
||||||
|
|||||||
@@ -43,6 +43,16 @@ public class BftHelpers {
|
|||||||
return Util.fastDivCeiling(2 * validatorCount, 3);
|
return Util.fastDivCeiling(2 * validatorCount, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate required future RC messages count quorum for a round change.
|
||||||
|
*
|
||||||
|
* @param validatorCount the validator count
|
||||||
|
* @return Required number of future round change messages to reach quorum for a round change.
|
||||||
|
*/
|
||||||
|
public static int calculateRequiredFutureRCQuorum(final int validatorCount) {
|
||||||
|
return (validatorCount - 1) / 3 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare message count for quorum.
|
* Prepare message count for quorum.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -83,8 +83,7 @@ public class RoundTimer {
|
|||||||
// Once we are up to round 2 start logging round expiries
|
// Once we are up to round 2 start logging round expiries
|
||||||
if (round.getRoundNumber() >= 2) {
|
if (round.getRoundNumber() >= 2) {
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"BFT round {} expired. Moved to round {} which will expire in {} seconds",
|
"Moved to round {} which will expire in {} seconds",
|
||||||
round.getRoundNumber() - 1,
|
|
||||||
round.getRoundNumber(),
|
round.getRoundNumber(),
|
||||||
(expiryTime / 1000));
|
(expiryTime / 1000));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,4 +63,39 @@ public class BftHelpersTest {
|
|||||||
public void calculateRequiredValidatorQuorum20Validator() {
|
public void calculateRequiredValidatorQuorum20Validator() {
|
||||||
Assertions.assertThat(BftHelpers.calculateRequiredValidatorQuorum(20)).isEqualTo(14);
|
Assertions.assertThat(BftHelpers.calculateRequiredValidatorQuorum(20)).isEqualTo(14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum4Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(4)).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum6Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(6)).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum7Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(7)).isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum9Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(9)).isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum10Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(10)).isEqualTo(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum13Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(13)).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateRequiredFutureRCQuorum15Validator() {
|
||||||
|
Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(15)).isEqualTo(5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager {
|
|||||||
|
|
||||||
private Optional<PreparedCertificate> latestPreparedCertificate = Optional.empty();
|
private Optional<PreparedCertificate> latestPreparedCertificate = Optional.empty();
|
||||||
private Optional<QbftRound> currentRound = Optional.empty();
|
private Optional<QbftRound> currentRound = Optional.empty();
|
||||||
|
private boolean isEarlyRoundChangeEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Qbft block height manager.
|
* Instantiates a new Qbft block height manager.
|
||||||
@@ -115,6 +116,39 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager {
|
|||||||
finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader);
|
finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Qbft block height manager. Secondary constructor with early round change
|
||||||
|
* option.
|
||||||
|
*
|
||||||
|
* @param parentHeader the parent header
|
||||||
|
* @param finalState the final state
|
||||||
|
* @param roundChangeManager the round change manager
|
||||||
|
* @param qbftRoundFactory the qbft round factory
|
||||||
|
* @param clock the clock
|
||||||
|
* @param messageValidatorFactory the message validator factory
|
||||||
|
* @param messageFactory the message factory
|
||||||
|
* @param isEarlyRoundChangeEnabled enable round change when f+1 RC messages are received
|
||||||
|
*/
|
||||||
|
public QbftBlockHeightManager(
|
||||||
|
final BlockHeader parentHeader,
|
||||||
|
final BftFinalState finalState,
|
||||||
|
final RoundChangeManager roundChangeManager,
|
||||||
|
final QbftRoundFactory qbftRoundFactory,
|
||||||
|
final Clock clock,
|
||||||
|
final MessageValidatorFactory messageValidatorFactory,
|
||||||
|
final MessageFactory messageFactory,
|
||||||
|
final boolean isEarlyRoundChangeEnabled) {
|
||||||
|
this(
|
||||||
|
parentHeader,
|
||||||
|
finalState,
|
||||||
|
roundChangeManager,
|
||||||
|
qbftRoundFactory,
|
||||||
|
clock,
|
||||||
|
messageValidatorFactory,
|
||||||
|
messageFactory);
|
||||||
|
this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleBlockTimerExpiry(final ConsensusRoundIdentifier roundIdentifier) {
|
public void handleBlockTimerExpiry(final ConsensusRoundIdentifier roundIdentifier) {
|
||||||
if (currentRound.isPresent()) {
|
if (currentRound.isPresent()) {
|
||||||
@@ -227,23 +261,36 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doRoundChange(qbftRound.getRoundIdentifier().getRoundNumber() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void doRoundChange(final int newRoundNumber) {
|
||||||
|
|
||||||
|
if (currentRound.isPresent()
|
||||||
|
&& currentRound.get().getRoundIdentifier().getRoundNumber() >= newRoundNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Round has expired, creating PreparedCertificate and notifying peers. round={}",
|
"Round has expired or changing based on RC quorum, creating PreparedCertificate and notifying peers. round={}",
|
||||||
qbftRound.getRoundIdentifier());
|
currentRound.get().getRoundIdentifier());
|
||||||
final Optional<PreparedCertificate> preparedCertificate =
|
final Optional<PreparedCertificate> preparedCertificate =
|
||||||
qbftRound.constructPreparedCertificate();
|
currentRound.get().constructPreparedCertificate();
|
||||||
|
|
||||||
if (preparedCertificate.isPresent()) {
|
if (preparedCertificate.isPresent()) {
|
||||||
latestPreparedCertificate = preparedCertificate;
|
latestPreparedCertificate = preparedCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
startNewRound(qbftRound.getRoundIdentifier().getRoundNumber() + 1);
|
startNewRound(newRoundNumber);
|
||||||
qbftRound = currentRound.get();
|
if (currentRound.isEmpty()) {
|
||||||
|
LOG.info("Failed to start round ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QbftRound qbftRoundNew = currentRound.get();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final RoundChange localRoundChange =
|
final RoundChange localRoundChange =
|
||||||
messageFactory.createRoundChange(
|
messageFactory.createRoundChange(
|
||||||
qbftRound.getRoundIdentifier(), latestPreparedCertificate);
|
qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate);
|
||||||
|
|
||||||
// Its possible the locally created RoundChange triggers the transmission of a NewRound
|
// Its possible the locally created RoundChange triggers the transmission of a NewRound
|
||||||
// message - so it must be handled accordingly.
|
// message - so it must be handled accordingly.
|
||||||
@@ -252,7 +299,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager {
|
|||||||
LOG.warn("Failed to create signed RoundChange message.", e);
|
LOG.warn("Failed to create signed RoundChange message.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
transmitter.multicastRoundChange(qbftRound.getRoundIdentifier(), latestPreparedCertificate);
|
transmitter.multicastRoundChange(qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -333,24 +380,55 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager {
|
|||||||
final Optional<Collection<RoundChange>> result =
|
final Optional<Collection<RoundChange>> result =
|
||||||
roundChangeManager.appendRoundChangeMessage(message);
|
roundChangeManager.appendRoundChangeMessage(message);
|
||||||
|
|
||||||
if (result.isPresent()) {
|
if (!isEarlyRoundChangeEnabled) {
|
||||||
LOG.debug(
|
if (result.isPresent()) {
|
||||||
"Received sufficient RoundChange messages to change round to targetRound={}",
|
LOG.debug(
|
||||||
targetRound);
|
"Received sufficient RoundChange messages to change round to targetRound={}",
|
||||||
if (messageAge == MessageAge.FUTURE_ROUND) {
|
targetRound);
|
||||||
startNewRound(targetRound.getRoundNumber());
|
if (messageAge == MessageAge.FUTURE_ROUND) {
|
||||||
}
|
startNewRound(targetRound.getRoundNumber());
|
||||||
|
|
||||||
final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get());
|
|
||||||
|
|
||||||
if (finalState.isLocalNodeProposerForRound(targetRound)) {
|
|
||||||
if (currentRound.isEmpty()) {
|
|
||||||
startNewRound(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get());
|
||||||
|
|
||||||
|
if (finalState.isLocalNodeProposerForRound(targetRound)) {
|
||||||
|
if (currentRound.isEmpty()) {
|
||||||
|
startNewRound(0);
|
||||||
|
}
|
||||||
|
currentRound
|
||||||
|
.get()
|
||||||
|
.startRoundWith(roundChangeMetadata, TimeUnit.MILLISECONDS.toSeconds(clock.millis()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (currentRound.isEmpty()) {
|
||||||
|
startNewRound(0);
|
||||||
|
}
|
||||||
|
int currentRoundNumber = currentRound.get().getRoundIdentifier().getRoundNumber();
|
||||||
|
// If this node is proposer for the current round, check if quorum is achieved for RC messages
|
||||||
|
// aiming this round
|
||||||
|
if (targetRound.getRoundNumber() == currentRoundNumber
|
||||||
|
&& finalState.isLocalNodeProposerForRound(targetRound)
|
||||||
|
&& result.isPresent()) {
|
||||||
|
|
||||||
|
final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get());
|
||||||
|
|
||||||
currentRound
|
currentRound
|
||||||
.get()
|
.get()
|
||||||
.startRoundWith(roundChangeMetadata, TimeUnit.MILLISECONDS.toSeconds(clock.millis()));
|
.startRoundWith(roundChangeMetadata, TimeUnit.MILLISECONDS.toSeconds(clock.millis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if f+1 RC messages for future rounds are received
|
||||||
|
QbftRound qbftRound = currentRound.get();
|
||||||
|
Optional<Integer> nextHigherRound =
|
||||||
|
roundChangeManager.futureRCQuorumReceived(qbftRound.getRoundIdentifier());
|
||||||
|
if (nextHigherRound.isPresent()) {
|
||||||
|
LOG.info(
|
||||||
|
"Received sufficient RoundChange messages to change round to targetRound={}",
|
||||||
|
nextHigherRound.get());
|
||||||
|
doRoundChange(nextHigherRound.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public class QbftBlockHeightManagerFactory {
|
|||||||
private final MessageValidatorFactory messageValidatorFactory;
|
private final MessageValidatorFactory messageValidatorFactory;
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
private final ValidatorModeTransitionLogger validatorModeTransitionLogger;
|
private final ValidatorModeTransitionLogger validatorModeTransitionLogger;
|
||||||
|
private boolean isEarlyRoundChangeEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Qbft block height manager factory.
|
* Instantiates a new Qbft block height manager factory.
|
||||||
@@ -75,22 +76,60 @@ public class QbftBlockHeightManagerFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets early round change enabled.
|
||||||
|
*
|
||||||
|
* @param isEarlyRoundChangeEnabled the is early round change enabled
|
||||||
|
*/
|
||||||
|
public void isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) {
|
||||||
|
this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
private BaseQbftBlockHeightManager createNoOpBlockHeightManager(final BlockHeader parentHeader) {
|
private BaseQbftBlockHeightManager createNoOpBlockHeightManager(final BlockHeader parentHeader) {
|
||||||
return new NoOpBlockHeightManager(parentHeader);
|
return new NoOpBlockHeightManager(parentHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseQbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) {
|
private BaseQbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) {
|
||||||
return new QbftBlockHeightManager(
|
|
||||||
parentHeader,
|
QbftBlockHeightManager qbftBlockHeightManager;
|
||||||
finalState,
|
RoundChangeManager roundChangeManager;
|
||||||
new RoundChangeManager(
|
|
||||||
BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()),
|
if (isEarlyRoundChangeEnabled) {
|
||||||
messageValidatorFactory.createRoundChangeMessageValidator(
|
roundChangeManager =
|
||||||
parentHeader.getNumber() + 1L, parentHeader),
|
new RoundChangeManager(
|
||||||
finalState.getLocalAddress()),
|
BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()),
|
||||||
roundFactory,
|
BftHelpers.calculateRequiredFutureRCQuorum(finalState.getValidators().size()),
|
||||||
finalState.getClock(),
|
messageValidatorFactory.createRoundChangeMessageValidator(
|
||||||
messageValidatorFactory,
|
parentHeader.getNumber() + 1L, parentHeader),
|
||||||
messageFactory);
|
finalState.getLocalAddress());
|
||||||
|
qbftBlockHeightManager =
|
||||||
|
new QbftBlockHeightManager(
|
||||||
|
parentHeader,
|
||||||
|
finalState,
|
||||||
|
roundChangeManager,
|
||||||
|
roundFactory,
|
||||||
|
finalState.getClock(),
|
||||||
|
messageValidatorFactory,
|
||||||
|
messageFactory,
|
||||||
|
true);
|
||||||
|
} else {
|
||||||
|
roundChangeManager =
|
||||||
|
new RoundChangeManager(
|
||||||
|
BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()),
|
||||||
|
messageValidatorFactory.createRoundChangeMessageValidator(
|
||||||
|
parentHeader.getNumber() + 1L, parentHeader),
|
||||||
|
finalState.getLocalAddress());
|
||||||
|
qbftBlockHeightManager =
|
||||||
|
new QbftBlockHeightManager(
|
||||||
|
parentHeader,
|
||||||
|
finalState,
|
||||||
|
roundChangeManager,
|
||||||
|
roundFactory,
|
||||||
|
finalState.getClock(),
|
||||||
|
messageValidatorFactory,
|
||||||
|
messageFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return qbftBlockHeightManager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.hyperledger.besu.datatypes.Address;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
@@ -75,7 +76,7 @@ public class RoundChangeManager {
|
|||||||
*
|
*
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
public boolean roundChangeReady() {
|
public boolean roundChangeQuorumReceived() {
|
||||||
return receivedMessages.size() >= quorum && !actioned;
|
return receivedMessages.size() >= quorum && !actioned;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ public class RoundChangeManager {
|
|||||||
* @return the collection
|
* @return the collection
|
||||||
*/
|
*/
|
||||||
public Collection<RoundChange> createRoundChangeCertificate() {
|
public Collection<RoundChange> createRoundChangeCertificate() {
|
||||||
if (roundChangeReady()) {
|
if (roundChangeQuorumReceived()) {
|
||||||
actioned = true;
|
actioned = true;
|
||||||
return receivedMessages.values();
|
return receivedMessages.values();
|
||||||
} else {
|
} else {
|
||||||
@@ -104,6 +105,7 @@ public class RoundChangeManager {
|
|||||||
private final Map<Address, ConsensusRoundIdentifier> roundSummary = Maps.newHashMap();
|
private final Map<Address, ConsensusRoundIdentifier> roundSummary = Maps.newHashMap();
|
||||||
|
|
||||||
private final long quorum;
|
private final long quorum;
|
||||||
|
private long rcQuorum;
|
||||||
private final RoundChangeMessageValidator roundChangeMessageValidator;
|
private final RoundChangeMessageValidator roundChangeMessageValidator;
|
||||||
private final Address localAddress;
|
private final Address localAddress;
|
||||||
|
|
||||||
@@ -123,6 +125,23 @@ public class RoundChangeManager {
|
|||||||
this.localAddress = localAddress;
|
this.localAddress = localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Round change manager.
|
||||||
|
*
|
||||||
|
* @param quorum the quorum
|
||||||
|
* @param rcQuorum quorum for round change messages
|
||||||
|
* @param roundChangeMessageValidator the round change message validator
|
||||||
|
* @param localAddress this node's address
|
||||||
|
*/
|
||||||
|
public RoundChangeManager(
|
||||||
|
final long quorum,
|
||||||
|
final long rcQuorum,
|
||||||
|
final RoundChangeMessageValidator roundChangeMessageValidator,
|
||||||
|
final Address localAddress) {
|
||||||
|
this(quorum, roundChangeMessageValidator, localAddress);
|
||||||
|
this.rcQuorum = rcQuorum;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the latest round for a node, and if chain is stalled log a summary of which round each
|
* Store the latest round for a node, and if chain is stalled log a summary of which round each
|
||||||
* address is on
|
* address is on
|
||||||
@@ -130,6 +149,10 @@ public class RoundChangeManager {
|
|||||||
* @param message the round-change message that has just been received
|
* @param message the round-change message that has just been received
|
||||||
*/
|
*/
|
||||||
public void storeAndLogRoundChangeSummary(final RoundChange message) {
|
public void storeAndLogRoundChangeSummary(final RoundChange message) {
|
||||||
|
if (!isMessageValid(message)) {
|
||||||
|
LOG.info("RoundChange message is invalid .");
|
||||||
|
return;
|
||||||
|
}
|
||||||
roundSummary.put(message.getAuthor(), message.getRoundIdentifier());
|
roundSummary.put(message.getAuthor(), message.getRoundIdentifier());
|
||||||
if (roundChangeCache.keySet().stream()
|
if (roundChangeCache.keySet().stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@@ -147,6 +170,39 @@ public class RoundChangeManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a quorum of round change messages has been received for a round higher than the
|
||||||
|
* current round
|
||||||
|
*
|
||||||
|
* @param currentRoundIdentifier the current round identifier
|
||||||
|
* @return the next higher round number if quorum is reached, otherwise empty Optional
|
||||||
|
*/
|
||||||
|
public Optional<Integer> futureRCQuorumReceived(
|
||||||
|
final ConsensusRoundIdentifier currentRoundIdentifier) {
|
||||||
|
// Iterate through elements of round summary, identify ones with round number higher than
|
||||||
|
// current,
|
||||||
|
// tracking minimum of those and return the next higher round number if quorum is reached
|
||||||
|
|
||||||
|
// Filter out entries with round number greater than current round
|
||||||
|
// and collect their round numbers
|
||||||
|
Map<Address, Integer> higherRounds =
|
||||||
|
roundSummary.entrySet().stream()
|
||||||
|
.filter(entry -> isAFutureRound(entry.getValue(), currentRoundIdentifier))
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getRoundNumber()));
|
||||||
|
|
||||||
|
LOG.debug("Higher rounds size ={} rcquorum = {}", higherRounds.size(), rcQuorum);
|
||||||
|
|
||||||
|
// Check if we have at least f + 1 validators at higher rounds
|
||||||
|
if (higherRounds.size() >= rcQuorum) {
|
||||||
|
// Find the minimum round that is greater than the current round
|
||||||
|
return Optional.of(higherRounds.values().stream().min(Integer::compareTo).orElseThrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If quorum is not reached, return empty Optional
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the round message to this manager and return a certificate if it passes the threshold
|
* Adds the round message to this manager and return a certificate if it passes the threshold
|
||||||
*
|
*
|
||||||
@@ -163,7 +219,7 @@ public class RoundChangeManager {
|
|||||||
|
|
||||||
final RoundChangeStatus roundChangeStatus = storeRoundChangeMessage(msg);
|
final RoundChangeStatus roundChangeStatus = storeRoundChangeMessage(msg);
|
||||||
|
|
||||||
if (roundChangeStatus.roundChangeReady()) {
|
if (roundChangeStatus.roundChangeQuorumReceived()) {
|
||||||
return Optional.of(roundChangeStatus.createRoundChangeCertificate());
|
return Optional.of(roundChangeStatus.createRoundChangeCertificate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,4 +254,9 @@ public class RoundChangeManager {
|
|||||||
final ConsensusRoundIdentifier left, final ConsensusRoundIdentifier right) {
|
final ConsensusRoundIdentifier left, final ConsensusRoundIdentifier right) {
|
||||||
return left.getRoundNumber() < right.getRoundNumber();
|
return left.getRoundNumber() < right.getRoundNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAFutureRound(
|
||||||
|
final ConsensusRoundIdentifier left, final ConsensusRoundIdentifier right) {
|
||||||
|
return left.getRoundNumber() > right.getRoundNumber();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
|
|||||||
import org.hyperledger.besu.consensus.qbft.core.validation.FutureRoundProposalMessageValidator;
|
import org.hyperledger.besu.consensus.qbft.core.validation.FutureRoundProposalMessageValidator;
|
||||||
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator;
|
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidator;
|
||||||
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory;
|
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory;
|
||||||
|
import org.hyperledger.besu.consensus.qbft.core.validation.RoundChangeMessageValidator;
|
||||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
||||||
import org.hyperledger.besu.cryptoservices.NodeKey;
|
import org.hyperledger.besu.cryptoservices.NodeKey;
|
||||||
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
import org.hyperledger.besu.cryptoservices.NodeKeyUtils;
|
||||||
@@ -138,7 +139,7 @@ public class QbftBlockHeightManagerTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i <= 3; i++) {
|
||||||
final NodeKey nodeKey = NodeKeyUtils.generate();
|
final NodeKey nodeKey = NodeKeyUtils.generate();
|
||||||
validators.add(Util.publicKeyToAddress(nodeKey.getPublicKey()));
|
validators.add(Util.publicKeyToAddress(nodeKey.getPublicKey()));
|
||||||
validatorMessageFactory.add(new MessageFactory(nodeKey));
|
validatorMessageFactory.add(new MessageFactory(nodeKey));
|
||||||
@@ -602,4 +603,42 @@ public class QbftBlockHeightManagerTest {
|
|||||||
verify(blockTimer, times(0)).getEmptyBlockPeriodSeconds();
|
verify(blockTimer, times(0)).getEmptyBlockPeriodSeconds();
|
||||||
verify(blockTimer, times(0)).getBlockPeriodSeconds();
|
verify(blockTimer, times(0)).getBlockPeriodSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundChangeTriggeredUponReceivingFPlusOneRoundChanges() {
|
||||||
|
final ConsensusRoundIdentifier futureRoundIdentifier1 = createFrom(roundIdentifier, 0, +2);
|
||||||
|
final ConsensusRoundIdentifier futureRoundIdentifier2 = createFrom(roundIdentifier, 0, +3);
|
||||||
|
|
||||||
|
final RoundChange roundChange1 =
|
||||||
|
validatorMessageFactory.get(0).createRoundChange(futureRoundIdentifier1, Optional.empty());
|
||||||
|
final RoundChange roundChange2 =
|
||||||
|
validatorMessageFactory.get(1).createRoundChange(futureRoundIdentifier2, Optional.empty());
|
||||||
|
|
||||||
|
RoundChangeMessageValidator roundChangeMessageValidator =
|
||||||
|
mock(RoundChangeMessageValidator.class);
|
||||||
|
when(roundChangeMessageValidator.validate(any())).thenReturn(true);
|
||||||
|
|
||||||
|
// Instantiate the real RoundChangeManager
|
||||||
|
final RoundChangeManager roundChangeManager =
|
||||||
|
new RoundChangeManager(3, 2, roundChangeMessageValidator, validators.get(2));
|
||||||
|
|
||||||
|
when(finalState.isLocalNodeProposerForRound(any())).thenReturn(false);
|
||||||
|
|
||||||
|
final QbftBlockHeightManager manager =
|
||||||
|
new QbftBlockHeightManager(
|
||||||
|
headerTestFixture.buildHeader(),
|
||||||
|
finalState,
|
||||||
|
roundChangeManager,
|
||||||
|
roundFactory,
|
||||||
|
clock,
|
||||||
|
messageValidatorFactory,
|
||||||
|
validatorMessageFactory.get(2),
|
||||||
|
true); // Enable early round change
|
||||||
|
|
||||||
|
manager.handleRoundChangePayload(roundChange1);
|
||||||
|
manager.handleRoundChangePayload(roundChange2);
|
||||||
|
|
||||||
|
verify(roundFactory, times(1))
|
||||||
|
.createNewRound(any(), eq(futureRoundIdentifier1.getRoundNumber()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,25 @@ public enum RequestType {
|
|||||||
case 0x01 -> WITHDRAWAL;
|
case 0x01 -> WITHDRAWAL;
|
||||||
case 0x02 -> CONSOLIDATION;
|
case 0x02 -> CONSOLIDATION;
|
||||||
default ->
|
default ->
|
||||||
throw new IllegalArgumentException(
|
throw new InvalidRequestTypeException(
|
||||||
String.format("Unsupported request type: 0x%02X", serializedTypeValue));
|
String.format("Unsupported request type: 0x%02X", serializedTypeValue));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an invalid request type is encountered.
|
||||||
|
*
|
||||||
|
* <p>This exception is thrown when a serialized type value does not correspond to any {@link
|
||||||
|
* RequestType}.
|
||||||
|
*/
|
||||||
|
public static class InvalidRequestTypeException extends IllegalArgumentException {
|
||||||
|
/**
|
||||||
|
* Constructs an {@link InvalidRequestTypeException} with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param message the detail message.
|
||||||
|
*/
|
||||||
|
public InvalidRequestTypeException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.hyperledger.besu.datatypes;
|
package org.hyperledger.besu.datatypes;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -35,6 +37,7 @@ public class StateOverride {
|
|||||||
private final Optional<Wei> balance;
|
private final Optional<Wei> balance;
|
||||||
private final Optional<Long> nonce;
|
private final Optional<Long> nonce;
|
||||||
private final Optional<String> code;
|
private final Optional<String> code;
|
||||||
|
private final Optional<Map<String, String>> state;
|
||||||
private final Optional<Map<String, String>> stateDiff;
|
private final Optional<Map<String, String>> stateDiff;
|
||||||
private final Optional<Address> movePrecompileToAddress;
|
private final Optional<Address> movePrecompileToAddress;
|
||||||
|
|
||||||
@@ -42,11 +45,13 @@ public class StateOverride {
|
|||||||
final Optional<Wei> balance,
|
final Optional<Wei> balance,
|
||||||
final Optional<Long> nonce,
|
final Optional<Long> nonce,
|
||||||
final Optional<String> code,
|
final Optional<String> code,
|
||||||
|
final Optional<Map<String, String>> state,
|
||||||
final Optional<Map<String, String>> stateDiff,
|
final Optional<Map<String, String>> stateDiff,
|
||||||
final Optional<Address> movePrecompileToAddress) {
|
final Optional<Address> movePrecompileToAddress) {
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
|
this.state = state;
|
||||||
this.stateDiff = stateDiff;
|
this.stateDiff = stateDiff;
|
||||||
this.movePrecompileToAddress = movePrecompileToAddress;
|
this.movePrecompileToAddress = movePrecompileToAddress;
|
||||||
}
|
}
|
||||||
@@ -83,6 +88,15 @@ public class StateOverride {
|
|||||||
*
|
*
|
||||||
* @return the state override map if present
|
* @return the state override map if present
|
||||||
*/
|
*/
|
||||||
|
public Optional<Map<String, String>> getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state diff override map
|
||||||
|
*
|
||||||
|
* @return the state diff override map if present
|
||||||
|
*/
|
||||||
public Optional<Map<String, String>> getStateDiff() {
|
public Optional<Map<String, String>> getStateDiff() {
|
||||||
return stateDiff;
|
return stateDiff;
|
||||||
}
|
}
|
||||||
@@ -102,6 +116,7 @@ public class StateOverride {
|
|||||||
private Optional<Wei> balance = Optional.empty();
|
private Optional<Wei> balance = Optional.empty();
|
||||||
private Optional<Long> nonce = Optional.empty();
|
private Optional<Long> nonce = Optional.empty();
|
||||||
private Optional<String> code = Optional.empty();
|
private Optional<String> code = Optional.empty();
|
||||||
|
private Optional<Map<String, String>> state = Optional.empty();
|
||||||
private Optional<Map<String, String>> stateDiff = Optional.empty();
|
private Optional<Map<String, String>> stateDiff = Optional.empty();
|
||||||
private Optional<Address> movePrecompileToAddress = Optional.empty();
|
private Optional<Address> movePrecompileToAddress = Optional.empty();
|
||||||
|
|
||||||
@@ -141,6 +156,17 @@ public class StateOverride {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the state override
|
||||||
|
*
|
||||||
|
* @param state the map of state overrides
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
public Builder withState(final Map<String, String> state) {
|
||||||
|
this.state = Optional.ofNullable(state);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the state diff override
|
* Sets the state diff override
|
||||||
*
|
*
|
||||||
@@ -169,7 +195,8 @@ public class StateOverride {
|
|||||||
* @return account override
|
* @return account override
|
||||||
*/
|
*/
|
||||||
public StateOverride build() {
|
public StateOverride build() {
|
||||||
return new StateOverride(balance, nonce, code, stateDiff, movePrecompileToAddress);
|
checkState(state.isEmpty() || stateDiff.isEmpty(), "Cannot set both state and stateDiff");
|
||||||
|
return new StateOverride(balance, nonce, code, state, stateDiff, movePrecompileToAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,12 +227,13 @@ public class StateOverride {
|
|||||||
return balance.equals(stateOverride.balance)
|
return balance.equals(stateOverride.balance)
|
||||||
&& nonce.equals(stateOverride.nonce)
|
&& nonce.equals(stateOverride.nonce)
|
||||||
&& code.equals(stateOverride.code)
|
&& code.equals(stateOverride.code)
|
||||||
|
&& state.equals(stateOverride.state)
|
||||||
&& stateDiff.equals(stateOverride.stateDiff);
|
&& stateDiff.equals(stateOverride.stateDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(balance, nonce, code, stateDiff);
|
return Objects.hash(balance, nonce, code, state, stateDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -217,6 +245,8 @@ public class StateOverride {
|
|||||||
+ nonce
|
+ nonce
|
||||||
+ ", code="
|
+ ", code="
|
||||||
+ code
|
+ code
|
||||||
|
+ ", state="
|
||||||
|
+ state
|
||||||
+ ", stateDiff="
|
+ ", stateDiff="
|
||||||
+ stateDiff
|
+ stateDiff
|
||||||
+ ", movePrecompileToAddress="
|
+ ", movePrecompileToAddress="
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
|||||||
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
|
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
|
||||||
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
|
|
||||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
||||||
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
|
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
|
||||||
import org.hyperledger.besu.ethereum.transaction.CallParameter;
|
import org.hyperledger.besu.ethereum.transaction.CallParameter;
|
||||||
@@ -163,14 +162,9 @@ public class PendingStateAdapter extends AdapterBase {
|
|||||||
final CallParameter param =
|
final CallParameter param =
|
||||||
new CallParameter(from, to, gasParam, gasPriceParam, valueParam, data);
|
new CallParameter(from, to, gasParam, gasPriceParam, valueParam, data);
|
||||||
|
|
||||||
ImmutableTransactionValidationParams.Builder transactionValidationParams =
|
|
||||||
ImmutableTransactionValidationParams.builder()
|
|
||||||
.from(TransactionValidationParams.transactionSimulator());
|
|
||||||
transactionValidationParams.isAllowExceedingBalance(true);
|
|
||||||
|
|
||||||
return transactionSimulator.process(
|
return transactionSimulator.process(
|
||||||
param,
|
param,
|
||||||
transactionValidationParams.build(),
|
TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce(),
|
||||||
OperationTracer.NO_TRACING,
|
OperationTracer.NO_TRACING,
|
||||||
(mutableWorldState, transactionSimulatorResult) ->
|
(mutableWorldState, transactionSimulatorResult) ->
|
||||||
transactionSimulatorResult.map(
|
transactionSimulatorResult.map(
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public abstract class AbstractDebugTraceBlock implements JsonRpcMethod {
|
|||||||
block ->
|
block ->
|
||||||
Tracer.processTracing(
|
Tracer.processTracing(
|
||||||
getBlockchainQueries(),
|
getBlockchainQueries(),
|
||||||
block.getHash(),
|
Optional.of(block.getHeader()),
|
||||||
traceableState -> {
|
traceableState -> {
|
||||||
List<DebugTraceTransactionResult> tracesList =
|
List<DebugTraceTransactionResult> tracesList =
|
||||||
Collections.synchronizedList(new ArrayList<>());
|
Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ public abstract class AbstractEstimateGas extends AbstractBlockParameterMethod {
|
|||||||
final boolean isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
|
final boolean isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
|
||||||
|
|
||||||
return isAllowExceedingBalance
|
return isAllowExceedingBalance
|
||||||
? TransactionValidationParams.transactionSimulatorAllowExceedingBalance()
|
? TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce()
|
||||||
: TransactionValidationParams.transactionSimulator();
|
: TransactionValidationParams.transactionSimulatorAllowFutureNonce();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class DebugTraceCall extends AbstractTraceCall {
|
public class DebugTraceCall extends AbstractTraceCall {
|
||||||
|
private static final TransactionValidationParams TRANSACTION_VALIDATION_PARAMS =
|
||||||
|
ImmutableTransactionValidationParams.builder()
|
||||||
|
.from(TransactionValidationParams.transactionSimulator())
|
||||||
|
.isAllowFutureNonce(true)
|
||||||
|
.isAllowExceedingBalance(true)
|
||||||
|
.allowUnderpriced(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
public DebugTraceCall(
|
public DebugTraceCall(
|
||||||
final BlockchainQueries blockchainQueries,
|
final BlockchainQueries blockchainQueries,
|
||||||
@@ -103,10 +110,6 @@ public class DebugTraceCall extends AbstractTraceCall {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransactionValidationParams buildTransactionValidationParams() {
|
protected TransactionValidationParams buildTransactionValidationParams() {
|
||||||
return ImmutableTransactionValidationParams.builder()
|
return TRANSACTION_VALIDATION_PARAMS;
|
||||||
.from(TransactionValidationParams.transactionSimulator())
|
|
||||||
.isAllowExceedingBalance(true)
|
|
||||||
.allowUnderpriced(true)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,8 +169,8 @@ public class EthCall extends AbstractBlockParameterOrBlockHashMethod {
|
|||||||
isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
|
isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
return isAllowExceedingBalance
|
return isAllowExceedingBalance
|
||||||
? TransactionValidationParams.transactionSimulatorAllowExceedingBalance()
|
? TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce()
|
||||||
: TransactionValidationParams.transactionSimulator();
|
: TransactionValidationParams.transactionSimulatorAllowFutureNonce();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllowExceedingBalanceAutoSelection(
|
private boolean isAllowExceedingBalanceAutoSelection(
|
||||||
|
|||||||
@@ -202,13 +202,15 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
|||||||
final Optional<List<Request>> maybeRequests;
|
final Optional<List<Request>> maybeRequests;
|
||||||
try {
|
try {
|
||||||
maybeRequests = extractRequests(maybeRequestsParam);
|
maybeRequests = extractRequests(maybeRequestsParam);
|
||||||
} catch (RuntimeException ex) {
|
} catch (RequestType.InvalidRequestTypeException ex) {
|
||||||
return respondWithInvalid(
|
return respondWithInvalid(
|
||||||
reqId,
|
reqId,
|
||||||
blockParam,
|
blockParam,
|
||||||
mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null),
|
mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null),
|
||||||
INVALID,
|
INVALID,
|
||||||
"Invalid execution requests");
|
"Invalid execution requests");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getRequestsValidator(
|
if (!getRequestsValidator(
|
||||||
@@ -364,7 +366,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
|||||||
.mapToInt(List::size)
|
.mapToInt(List::size)
|
||||||
.sum(),
|
.sum(),
|
||||||
lastExecutionTime / 1000.0,
|
lastExecutionTime / 1000.0,
|
||||||
executionResult.getNbParallelizedTransations());
|
executionResult.getNbParallelizedTransactions());
|
||||||
return respondWith(reqId, blockParam, newBlockHeader.getHash(), VALID);
|
return respondWith(reqId, blockParam, newBlockHeader.getHash(), VALID);
|
||||||
} else {
|
} else {
|
||||||
if (executionResult.causedBy().isPresent()) {
|
if (executionResult.causedBy().isPresent()) {
|
||||||
@@ -591,14 +593,17 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
|||||||
if (maybeRequestsParam.isEmpty()) {
|
if (maybeRequestsParam.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return maybeRequestsParam.map(
|
return maybeRequestsParam.map(
|
||||||
requests ->
|
requests ->
|
||||||
requests.stream()
|
requests.stream()
|
||||||
.map(
|
.map(
|
||||||
s -> {
|
s -> {
|
||||||
final Bytes request = Bytes.fromHexString(s);
|
final Bytes request = Bytes.fromHexString(s);
|
||||||
return new Request(RequestType.of(request.get(0)), request.slice(1));
|
final Bytes requestData = request.slice(1);
|
||||||
|
if (requestData.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Request data cannot be empty");
|
||||||
|
}
|
||||||
|
return new Request(RequestType.of(request.get(0)), requestData);
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
@@ -607,7 +612,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
|||||||
final Block block,
|
final Block block,
|
||||||
final int blobCount,
|
final int blobCount,
|
||||||
final double timeInS,
|
final double timeInS,
|
||||||
final Optional<Integer> nbParallelizedTransations) {
|
final Optional<Integer> nbParallelizedTransactions) {
|
||||||
final StringBuilder message = new StringBuilder();
|
final StringBuilder message = new StringBuilder();
|
||||||
final int nbTransactions = block.getBody().getTransactions().size();
|
final int nbTransactions = block.getBody().getTransactions().size();
|
||||||
message.append("Imported #%,d (%s)|%5d tx");
|
message.append("Imported #%,d (%s)|%5d tx");
|
||||||
@@ -630,9 +635,9 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
|||||||
(block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(),
|
(block.getHeader().getGasUsed() * 100.0) / block.getHeader().getGasLimit(),
|
||||||
timeInS,
|
timeInS,
|
||||||
mgasPerSec));
|
mgasPerSec));
|
||||||
if (nbParallelizedTransations.isPresent()) {
|
if (nbParallelizedTransactions.isPresent()) {
|
||||||
double parallelizedTxPercentage =
|
double parallelizedTxPercentage =
|
||||||
(double) (nbParallelizedTransations.get() * 100) / nbTransactions;
|
(double) (nbParallelizedTransactions.get() * 100) / nbTransactions;
|
||||||
message.append("| parallel txs %5.1f%%");
|
message.append("| parallel txs %5.1f%%");
|
||||||
messageArgs.add(parallelizedTxPercentage);
|
messageArgs.add(parallelizedTxPercentage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class ForkSupportHelper {
|
|||||||
"Configuration error, no schedule for " + hardforkId.name() + " fork set");
|
"Configuration error, no schedule for " + hardforkId.name() + " fork set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockTimestamp < maybeForkMilestone.get()) {
|
if (Long.compareUnsigned(blockTimestamp, maybeForkMilestone.get()) < 0) {
|
||||||
return ValidationResult.invalid(
|
return ValidationResult.invalid(
|
||||||
RpcErrorType.UNSUPPORTED_FORK,
|
RpcErrorType.UNSUPPORTED_FORK,
|
||||||
hardforkId.name() + " configured to start at timestamp: " + maybeForkMilestone.get());
|
hardforkId.name() + " configured to start at timestamp: " + maybeForkMilestone.get());
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public enum RpcErrorType implements RpcMethodError {
|
|||||||
// Transaction validation failures
|
// Transaction validation failures
|
||||||
NONCE_TOO_LOW(-32001, "Nonce too low"),
|
NONCE_TOO_LOW(-32001, "Nonce too low"),
|
||||||
INVALID_TRANSACTION_SIGNATURE(-32002, "Invalid signature"),
|
INVALID_TRANSACTION_SIGNATURE(-32002, "Invalid signature"),
|
||||||
INVALID_TRANSACTION_TYPE(-32602, "Invalid transaction type"),
|
INVALID_TRANSACTION_TYPE(INVALID_PARAMS_ERROR_CODE, "Invalid transaction type"),
|
||||||
INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"),
|
INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"),
|
||||||
TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"),
|
TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"),
|
||||||
EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"),
|
EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"),
|
||||||
|
|||||||
@@ -130,8 +130,9 @@ public class TransactionCompleteResult implements TransactionResult {
|
|||||||
this.yParity = Quantity.create(transaction.getYParity());
|
this.yParity = Quantity.create(transaction.getYParity());
|
||||||
this.v =
|
this.v =
|
||||||
(transactionType == TransactionType.ACCESS_LIST
|
(transactionType == TransactionType.ACCESS_LIST
|
||||||
|| transactionType == TransactionType.EIP1559)
|
|| transactionType == TransactionType.EIP1559
|
||||||
|| transactionType == TransactionType.DELEGATE_CODE
|
|| transactionType == TransactionType.DELEGATE_CODE
|
||||||
|
|| transactionType == TransactionType.BLOB)
|
||||||
? Quantity.create(transaction.getYParity())
|
? Quantity.create(transaction.getYParity())
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ public class TransactionPendingResult implements TransactionResult {
|
|||||||
this.yParity = Quantity.create(transaction.getYParity());
|
this.yParity = Quantity.create(transaction.getYParity());
|
||||||
this.v =
|
this.v =
|
||||||
(transactionType == TransactionType.ACCESS_LIST
|
(transactionType == TransactionType.ACCESS_LIST
|
||||||
|| transactionType == TransactionType.EIP1559)
|
|| transactionType == TransactionType.EIP1559
|
||||||
|
|| transactionType == TransactionType.DELEGATE_CODE
|
||||||
|
|| transactionType == TransactionType.BLOB)
|
||||||
? Quantity.create(transaction.getYParity())
|
? Quantity.create(transaction.getYParity())
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.mock;
|
|||||||
import static org.mockito.Mockito.mockStatic;
|
import static org.mockito.Mockito.mockStatic;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.Hash;
|
|
||||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
||||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
|
||||||
@@ -33,6 +32,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.DebugTraceTran
|
|||||||
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
||||||
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
||||||
import org.hyperledger.besu.ethereum.core.Block;
|
import org.hyperledger.besu.ethereum.core.Block;
|
||||||
|
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
|
||||||
|
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
|
||||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
||||||
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
|
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
|
||||||
import org.hyperledger.besu.testutil.DeterministicEthScheduler;
|
import org.hyperledger.besu.testutil.DeterministicEthScheduler;
|
||||||
@@ -59,10 +60,7 @@ public class DebugTraceBlockByHashTest {
|
|||||||
@Mock private BlockchainQueries blockchainQueries;
|
@Mock private BlockchainQueries blockchainQueries;
|
||||||
@Mock private ObservableMetricsSystem metricsSystem;
|
@Mock private ObservableMetricsSystem metricsSystem;
|
||||||
@Mock private Blockchain blockchain;
|
@Mock private Blockchain blockchain;
|
||||||
@Mock private Block block;
|
|
||||||
private DebugTraceBlockByHash debugTraceBlockByHash;
|
private DebugTraceBlockByHash debugTraceBlockByHash;
|
||||||
private final Hash blockHash =
|
|
||||||
Hash.fromHexString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -79,13 +77,18 @@ public class DebugTraceBlockByHashTest {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Test
|
@Test
|
||||||
public void shouldReturnCorrectResponse() {
|
public void shouldReturnCorrectResponse() {
|
||||||
final Object[] params = new Object[] {blockHash};
|
final Block block =
|
||||||
|
new BlockDataGenerator()
|
||||||
|
.block(
|
||||||
|
BlockDataGenerator.BlockOptions.create()
|
||||||
|
.setBlockHeaderFunctions(new MainnetBlockHeaderFunctions()));
|
||||||
|
|
||||||
|
final Object[] params = new Object[] {block.getHash()};
|
||||||
final JsonRpcRequestContext request =
|
final JsonRpcRequestContext request =
|
||||||
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlockByHash", params));
|
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "debug_traceBlockByHash", params));
|
||||||
|
|
||||||
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
|
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
|
||||||
when(blockchain.getBlockByHash(blockHash)).thenReturn(Optional.of(block));
|
when(blockchain.getBlockByHash(block.getHash())).thenReturn(Optional.of(block));
|
||||||
when(block.getHash()).thenReturn(blockHash);
|
|
||||||
|
|
||||||
DebugTraceTransactionResult result1 = mock(DebugTraceTransactionResult.class);
|
DebugTraceTransactionResult result1 = mock(DebugTraceTransactionResult.class);
|
||||||
DebugTraceTransactionResult result2 = mock(DebugTraceTransactionResult.class);
|
DebugTraceTransactionResult result2 = mock(DebugTraceTransactionResult.class);
|
||||||
@@ -96,7 +99,10 @@ public class DebugTraceBlockByHashTest {
|
|||||||
mockedTracer
|
mockedTracer
|
||||||
.when(
|
.when(
|
||||||
() ->
|
() ->
|
||||||
Tracer.processTracing(eq(blockchainQueries), eq(blockHash), any(Function.class)))
|
Tracer.processTracing(
|
||||||
|
eq(blockchainQueries),
|
||||||
|
eq(Optional.of(block.getHeader())),
|
||||||
|
any(Function.class)))
|
||||||
.thenReturn(Optional.of(resultList));
|
.thenReturn(Optional.of(resultList));
|
||||||
|
|
||||||
final JsonRpcResponse jsonRpcResponse = debugTraceBlockByHash.response(request);
|
final JsonRpcResponse jsonRpcResponse = debugTraceBlockByHash.response(request);
|
||||||
|
|||||||
@@ -154,7 +154,9 @@ public class DebugTraceBlockTest {
|
|||||||
.when(
|
.when(
|
||||||
() ->
|
() ->
|
||||||
Tracer.processTracing(
|
Tracer.processTracing(
|
||||||
eq(blockchainQueries), eq(block.getHash()), any(Function.class)))
|
eq(blockchainQueries),
|
||||||
|
eq(Optional.of(block.getHeader())),
|
||||||
|
any(Function.class)))
|
||||||
.thenReturn(Optional.of(resultList));
|
.thenReturn(Optional.of(resultList));
|
||||||
|
|
||||||
final JsonRpcResponse jsonRpcResponse = debugTraceBlock.response(request);
|
final JsonRpcResponse jsonRpcResponse = debugTraceBlock.response(request);
|
||||||
|
|||||||
@@ -124,6 +124,27 @@ public class EthCallTest {
|
|||||||
assertThat(overrideMap).containsValue(override);
|
assertThat(overrideMap).containsValue(override);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stateOverridesWithState() {
|
||||||
|
StateOverrideMap expectedOverrides = new StateOverrideMap();
|
||||||
|
StateOverride override =
|
||||||
|
new StateOverride.Builder().withState(Map.of("0x1234", "0x5678")).build();
|
||||||
|
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
|
||||||
|
expectedOverrides.put(address, override);
|
||||||
|
|
||||||
|
final JsonRpcRequestContext request =
|
||||||
|
ethCallRequestWithStateOverrides(callParameter(), "latest", expectedOverrides);
|
||||||
|
|
||||||
|
Optional<StateOverrideMap> maybeOverrideMap = method.getAddressStateOverrideMap(request);
|
||||||
|
assertThat(maybeOverrideMap.isPresent()).isTrue();
|
||||||
|
StateOverrideMap overrideMap = maybeOverrideMap.get();
|
||||||
|
assertThat(overrideMap.keySet()).hasSize(1);
|
||||||
|
assertThat(overrideMap.values()).hasSize(1);
|
||||||
|
|
||||||
|
assertThat(overrideMap).containsKey(address);
|
||||||
|
assertThat(overrideMap).containsValue(override);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fullStateOverrides() {
|
public void fullStateOverrides() {
|
||||||
StateOverrideMap suppliedOverrides = new StateOverrideMap();
|
StateOverrideMap suppliedOverrides = new StateOverrideMap();
|
||||||
@@ -493,6 +514,7 @@ public class EthCallTest {
|
|||||||
ImmutableTransactionValidationParams.builder()
|
ImmutableTransactionValidationParams.builder()
|
||||||
.from(TransactionValidationParams.transactionSimulator())
|
.from(TransactionValidationParams.transactionSimulator())
|
||||||
.isAllowExceedingBalance(isAllowedExceedingBalance)
|
.isAllowExceedingBalance(isAllowedExceedingBalance)
|
||||||
|
.isAllowFutureNonce(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
verify(transactionSimulator)
|
verify(transactionSimulator)
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ public class EthEstimateGasTest {
|
|||||||
final JsonRpcRequestContext request =
|
final JsonRpcRequestContext request =
|
||||||
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
|
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
|
||||||
when(transactionSimulator.process(
|
when(transactionSimulator.process(
|
||||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
any(TransactionValidationParams.class),
|
any(TransactionValidationParams.class),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
@@ -193,11 +193,26 @@ public class EthEstimateGasTest {
|
|||||||
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
|
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldUseNonceParameterWhenIsPresent() {
|
||||||
|
final Wei gasPrice = Wei.of(1000);
|
||||||
|
final long nonce = 0L;
|
||||||
|
final JsonRpcRequestContext request =
|
||||||
|
ethEstimateGasRequest(
|
||||||
|
eip1559TransactionCallParameter(Optional.of(gasPrice), Optional.of(nonce)));
|
||||||
|
getMockTransactionSimulatorResult(
|
||||||
|
true, 1L, gasPrice, Optional.empty(), latestBlockHeader, Optional.of(nonce));
|
||||||
|
|
||||||
|
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L));
|
||||||
|
assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotErrorWhenGasPricePresentForEip1559Transaction() {
|
public void shouldNotErrorWhenGasPricePresentForEip1559Transaction() {
|
||||||
final Wei gasPrice = Wei.of(1000);
|
final Wei gasPrice = Wei.of(1000);
|
||||||
final JsonRpcRequestContext request =
|
final JsonRpcRequestContext request =
|
||||||
ethEstimateGasRequest(eip1559TransactionCallParameter(Optional.of(gasPrice)));
|
ethEstimateGasRequest(
|
||||||
|
eip1559TransactionCallParameter(Optional.of(gasPrice), Optional.empty()));
|
||||||
mockTransientProcessorResultGasEstimate(
|
mockTransientProcessorResultGasEstimate(
|
||||||
1L, true, gasPrice, Optional.empty(), latestBlockHeader);
|
1L, true, gasPrice, Optional.empty(), latestBlockHeader);
|
||||||
|
|
||||||
@@ -379,9 +394,11 @@ public class EthEstimateGasTest {
|
|||||||
|
|
||||||
verify(transactionSimulator)
|
verify(transactionSimulator)
|
||||||
.process(
|
.process(
|
||||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
eq(TransactionValidationParams.transactionSimulatorAllowExceedingBalance()),
|
eq(
|
||||||
|
TransactionValidationParams
|
||||||
|
.transactionSimulatorAllowExceedingBalanceAndFutureNonceParams),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
eq(latestBlockHeader));
|
eq(latestBlockHeader));
|
||||||
}
|
}
|
||||||
@@ -396,9 +413,9 @@ public class EthEstimateGasTest {
|
|||||||
|
|
||||||
verify(transactionSimulator)
|
verify(transactionSimulator)
|
||||||
.process(
|
.process(
|
||||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
eq(TransactionValidationParams.transactionSimulator()),
|
eq(TransactionValidationParams.transactionSimulatorAllowFutureNonce()),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
eq(latestBlockHeader));
|
eq(latestBlockHeader));
|
||||||
}
|
}
|
||||||
@@ -456,7 +473,8 @@ public class EthEstimateGasTest {
|
|||||||
final String validationFailedErrorMessage,
|
final String validationFailedErrorMessage,
|
||||||
final BlockHeader blockHeader) {
|
final BlockHeader blockHeader) {
|
||||||
final TransactionSimulatorResult mockTxSimResult =
|
final TransactionSimulatorResult mockTxSimResult =
|
||||||
getMockTransactionSimulatorResult(false, 0, Wei.ZERO, Optional.empty(), blockHeader);
|
getMockTransactionSimulatorResult(
|
||||||
|
false, 0, Wei.ZERO, Optional.empty(), blockHeader, Optional.empty());
|
||||||
when(mockTxSimResult.getValidationResult())
|
when(mockTxSimResult.getValidationResult())
|
||||||
.thenReturn(
|
.thenReturn(
|
||||||
validationFailedErrorMessage == null
|
validationFailedErrorMessage == null
|
||||||
@@ -493,7 +511,7 @@ public class EthEstimateGasTest {
|
|||||||
final Optional<Bytes> revertReason,
|
final Optional<Bytes> revertReason,
|
||||||
final BlockHeader blockHeader) {
|
final BlockHeader blockHeader) {
|
||||||
getMockTransactionSimulatorResult(
|
getMockTransactionSimulatorResult(
|
||||||
isSuccessful, estimateGas, gasPrice, revertReason, blockHeader);
|
isSuccessful, estimateGas, gasPrice, revertReason, blockHeader, Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ReferenceEquality")
|
@SuppressWarnings("ReferenceEquality")
|
||||||
@@ -502,11 +520,12 @@ public class EthEstimateGasTest {
|
|||||||
final long estimateGas,
|
final long estimateGas,
|
||||||
final Wei gasPrice,
|
final Wei gasPrice,
|
||||||
final Optional<Bytes> revertReason,
|
final Optional<Bytes> revertReason,
|
||||||
final BlockHeader blockHeader) {
|
final BlockHeader blockHeader,
|
||||||
|
final Optional<Long> maybeNonce) {
|
||||||
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
|
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
|
||||||
if (blockHeader == pendingBlockHeader) {
|
if (blockHeader == pendingBlockHeader) {
|
||||||
when(transactionSimulator.processOnPending(
|
when(transactionSimulator.processOnPending(
|
||||||
eq(modifiedLegacyTransactionCallParameter(gasPrice)),
|
eq(modifiedLegacyTransactionCallParameter(gasPrice, maybeNonce)),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
any(TransactionValidationParams.class),
|
any(TransactionValidationParams.class),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
@@ -521,7 +540,7 @@ public class EthEstimateGasTest {
|
|||||||
.thenReturn(Optional.of(mockTxSimResult));
|
.thenReturn(Optional.of(mockTxSimResult));
|
||||||
} else {
|
} else {
|
||||||
when(transactionSimulator.process(
|
when(transactionSimulator.process(
|
||||||
eq(modifiedLegacyTransactionCallParameter(gasPrice)),
|
eq(modifiedLegacyTransactionCallParameter(gasPrice, maybeNonce)),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
any(TransactionValidationParams.class),
|
any(TransactionValidationParams.class),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
@@ -536,7 +555,7 @@ public class EthEstimateGasTest {
|
|||||||
.thenReturn(Optional.of(mockTxSimResult));
|
.thenReturn(Optional.of(mockTxSimResult));
|
||||||
// for testing different combination of gasPrice params
|
// for testing different combination of gasPrice params
|
||||||
when(transactionSimulator.process(
|
when(transactionSimulator.process(
|
||||||
eq(modifiedEip1559TransactionCallParameter(Optional.of(gasPrice))),
|
eq(modifiedEip1559TransactionCallParameter(Optional.of(gasPrice), maybeNonce)),
|
||||||
eq(Optional.empty()), // no account overrides
|
eq(Optional.empty()), // no account overrides
|
||||||
any(TransactionValidationParams.class),
|
any(TransactionValidationParams.class),
|
||||||
any(OperationTracer.class),
|
any(OperationTracer.class),
|
||||||
@@ -569,7 +588,8 @@ public class EthEstimateGasTest {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CallParameter modifiedLegacyTransactionCallParameter(final Wei gasPrice) {
|
private CallParameter modifiedLegacyTransactionCallParameter(
|
||||||
|
final Wei gasPrice, final Optional<Long> maybeNonce) {
|
||||||
return new CallParameter(
|
return new CallParameter(
|
||||||
Address.fromHexString("0x0"),
|
Address.fromHexString("0x0"),
|
||||||
Address.fromHexString("0x0"),
|
Address.fromHexString("0x0"),
|
||||||
@@ -580,14 +600,15 @@ public class EthEstimateGasTest {
|
|||||||
Wei.ZERO,
|
Wei.ZERO,
|
||||||
Bytes.EMPTY,
|
Bytes.EMPTY,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty());
|
maybeNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CallParameter eip1559TransactionCallParameter() {
|
private CallParameter eip1559TransactionCallParameter() {
|
||||||
return eip1559TransactionCallParameter(Optional.empty());
|
return eip1559TransactionCallParameter(Optional.empty(), Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonCallParameter eip1559TransactionCallParameter(final Optional<Wei> maybeGasPrice) {
|
private JsonCallParameter eip1559TransactionCallParameter(
|
||||||
|
final Optional<Wei> maybeGasPrice, final Optional<Long> maybeNonce) {
|
||||||
return new JsonCallParameter.JsonCallParameterBuilder()
|
return new JsonCallParameter.JsonCallParameterBuilder()
|
||||||
.withFrom(Address.fromHexString("0x0"))
|
.withFrom(Address.fromHexString("0x0"))
|
||||||
.withTo(Address.fromHexString("0x0"))
|
.withTo(Address.fromHexString("0x0"))
|
||||||
@@ -597,14 +618,16 @@ public class EthEstimateGasTest {
|
|||||||
.withValue(Wei.ZERO)
|
.withValue(Wei.ZERO)
|
||||||
.withInput(Bytes.EMPTY)
|
.withInput(Bytes.EMPTY)
|
||||||
.withStrict(false)
|
.withStrict(false)
|
||||||
|
.withNonce(maybeNonce.map(UnsignedLongParameter::new).orElse(null))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CallParameter modifiedEip1559TransactionCallParameter() {
|
private CallParameter modifiedEip1559TransactionCallParameter() {
|
||||||
return modifiedEip1559TransactionCallParameter(Optional.empty());
|
return modifiedEip1559TransactionCallParameter(Optional.empty(), Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CallParameter modifiedEip1559TransactionCallParameter(final Optional<Wei> gasPrice) {
|
private CallParameter modifiedEip1559TransactionCallParameter(
|
||||||
|
final Optional<Wei> gasPrice, final Optional<Long> maybeNonce) {
|
||||||
return new CallParameter(
|
return new CallParameter(
|
||||||
Address.fromHexString("0x0"),
|
Address.fromHexString("0x0"),
|
||||||
Address.fromHexString("0x0"),
|
Address.fromHexString("0x0"),
|
||||||
@@ -615,7 +638,7 @@ public class EthEstimateGasTest {
|
|||||||
Wei.ZERO,
|
Wei.ZERO,
|
||||||
Bytes.EMPTY,
|
Bytes.EMPTY,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty());
|
maybeNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonRpcRequestContext ethEstimateGasRequest(final CallParameter callParameter) {
|
private JsonRpcRequestContext ethEstimateGasRequest(final CallParameter callParameter) {
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright contributors to 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.ethereum.api.jsonrpc.internal.methods.engine;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.PRAGUE;
|
||||||
|
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.ForkSupportHelper.validateForkSupported;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
||||||
|
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class ForkSupportHelperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validForkIfMilestoneOlderThanBlock() {
|
||||||
|
assertThat(validateForkSupported(PRAGUE, Optional.of(0L), 1))
|
||||||
|
.isEqualTo(ValidationResult.valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validForkIfMilestoneEqualToBlock() {
|
||||||
|
assertThat(validateForkSupported(PRAGUE, Optional.of(0L), 0))
|
||||||
|
.isEqualTo(ValidationResult.valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validForkWhenTimestampOverflowsSignedLong() {
|
||||||
|
long unsignedLongMaxValue = Long.parseUnsignedLong("18446744073709551615");
|
||||||
|
assertThat(validateForkSupported(PRAGUE, Optional.of(1L), unsignedLongMaxValue))
|
||||||
|
.isEqualTo(ValidationResult.valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unsupportedForkIfMilestoneMisconfigured() {
|
||||||
|
assertThat(validateForkSupported(PRAGUE, Optional.empty(), 0))
|
||||||
|
.isEqualTo(
|
||||||
|
ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK, "message equality ignored"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unsupportedForkIfBlockOlderThanMilestone() {
|
||||||
|
assertThat(validateForkSupported(PRAGUE, Optional.of(1L), 0))
|
||||||
|
.isEqualTo(
|
||||||
|
ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK, "message equality ignored"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"method": "debug_traceCall",
|
"method": "debug_traceCall",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
"to": "0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC",
|
"to": "0x0000f90827f1c53a10cb7a02335b175320002935",
|
||||||
"data": "0x000000000000000000000000000000000000000000000000000000000001A00E"
|
"data": "0x000000000000000000000000000000000000000000000000000000000001A00E"
|
||||||
},
|
},
|
||||||
"latest",
|
"latest",
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
{
|
||||||
|
"request" : {
|
||||||
|
"jsonrpc" : "2.0",
|
||||||
|
"method" : "debug_traceCall",
|
||||||
|
"params" : [ {
|
||||||
|
"from" : "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
|
||||||
|
"to" : "0x0050000000000000000000000000000000000000",
|
||||||
|
"gas" : "0xfffff2",
|
||||||
|
"gasPrice" : "0xef",
|
||||||
|
"value" : "0x0",
|
||||||
|
"data" : "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
"nonce" : "0x1F"
|
||||||
|
}, "latest",
|
||||||
|
{
|
||||||
|
"disableMemory": true, "disableStack": true, "disableStorage": true
|
||||||
|
} ],
|
||||||
|
"id" : 1
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"gas" : 22070,
|
||||||
|
"failed" : false,
|
||||||
|
"returnValue" : "f000000000000000000000000000000000000000000000000000000000000002",
|
||||||
|
"structLogs" : [ {
|
||||||
|
"pc" : 0,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755910,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 2,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755907,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 4,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755904,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 6,
|
||||||
|
"op" : "CALLDATASIZE",
|
||||||
|
"gas" : 16755901,
|
||||||
|
"gasCost" : 2,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 7,
|
||||||
|
"op" : "SUB",
|
||||||
|
"gas" : 16755899,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 8,
|
||||||
|
"op" : "DUP1",
|
||||||
|
"gas" : 16755896,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 9,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755893,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 11,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755890,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 13,
|
||||||
|
"op" : "CALLDATACOPY",
|
||||||
|
"gas" : 16755887,
|
||||||
|
"gasCost" : 9,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 14,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755878,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 16,
|
||||||
|
"op" : "CALLVALUE",
|
||||||
|
"gas" : 16755875,
|
||||||
|
"gasCost" : 2,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 17,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755873,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 19,
|
||||||
|
"op" : "CALLDATALOAD",
|
||||||
|
"gas" : 16755870,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 20,
|
||||||
|
"op" : "GAS",
|
||||||
|
"gas" : 16755867,
|
||||||
|
"gasCost" : 2,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 21,
|
||||||
|
"op" : "CALLCODE",
|
||||||
|
"gas" : 16755865,
|
||||||
|
"gasCost" : 16494066,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 0,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16493366,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 2,
|
||||||
|
"op" : "CALLDATALOAD",
|
||||||
|
"gas" : 16493363,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 3,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16493360,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 5,
|
||||||
|
"op" : "ADD",
|
||||||
|
"gas" : 16493357,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 6,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16493354,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 8,
|
||||||
|
"op" : "MSTORE",
|
||||||
|
"gas" : 16493351,
|
||||||
|
"gasCost" : 6,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 9,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16493345,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 11,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16493342,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 13,
|
||||||
|
"op" : "RETURN",
|
||||||
|
"gas" : 16493339,
|
||||||
|
"gasCost" : 0,
|
||||||
|
"depth" : 2
|
||||||
|
}, {
|
||||||
|
"pc" : 22,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755138,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 24,
|
||||||
|
"op" : "PUSH1",
|
||||||
|
"gas" : 16755135,
|
||||||
|
"gasCost" : 3,
|
||||||
|
"depth" : 1
|
||||||
|
}, {
|
||||||
|
"pc" : 26,
|
||||||
|
"op" : "RETURN",
|
||||||
|
"gas" : 16755132,
|
||||||
|
"gasCost" : 0,
|
||||||
|
"depth" : 1
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"id": 4,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_call",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||||
|
"data": "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029",
|
||||||
|
"nonce": "0x2f"
|
||||||
|
},
|
||||||
|
"latest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 4,
|
||||||
|
"result": "0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"id": 4,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_call",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||||
|
"data": "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029",
|
||||||
|
"nonce": "0x22"
|
||||||
|
},
|
||||||
|
"latest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 4,
|
||||||
|
"result": "0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"id": 3,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_estimateGas",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||||
|
"to": "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||||
|
"value": "0x1",
|
||||||
|
"nonce": "0x29"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 3,
|
||||||
|
"result": "0x5208"
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"id": 3,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_estimateGas",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||||
|
"to": "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||||
|
"value": "0x1",
|
||||||
|
"nonce": "0x22"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 3,
|
||||||
|
"result": "0x5208"
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"id": 3,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_estimateGas",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
|
||||||
|
"to": "0x8888f1f195afa192cfee860698584c030f4c9db1",
|
||||||
|
"value": "0x1",
|
||||||
|
"nonce": "0x2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 3,
|
||||||
|
"error": {
|
||||||
|
"code": -32001,
|
||||||
|
"message": "Nonce too low (transaction nonce 2 below sender account nonce 34)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statusCode": 200
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
"type": "0x3",
|
"type": "0x3",
|
||||||
"value": "0x0",
|
"value": "0x0",
|
||||||
"yParity": "0x0",
|
"yParity": "0x0",
|
||||||
|
"v" : "0x0",
|
||||||
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
||||||
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
||||||
"blobVersionedHashes": [
|
"blobVersionedHashes": [
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"type": "0x3",
|
"type": "0x3",
|
||||||
"value": "0x0",
|
"value": "0x0",
|
||||||
"yParity": "0x0",
|
"yParity": "0x0",
|
||||||
|
"v" : "0x0",
|
||||||
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
||||||
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
||||||
"blobVersionedHashes": [
|
"blobVersionedHashes": [
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"type": "0x3",
|
"type": "0x3",
|
||||||
"value": "0x0",
|
"value": "0x0",
|
||||||
"yParity": "0x0",
|
"yParity": "0x0",
|
||||||
|
"v" : "0x0",
|
||||||
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
"r": "0x6ae0612cfda43a9b464b10b4881c6fc2e4c24533cf89bbe07934da65c3ae49ce",
|
||||||
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
"s": "0x125387aeb222ec51130cf99cbdabf24bd4a881914faed69f254e4a3f4bc507fc",
|
||||||
"blobVersionedHashes": [
|
"blobVersionedHashes": [
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlockSi
|
|||||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector;
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector;
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector;
|
||||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector;
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector;
|
||||||
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.SkipSenderTransactionSelector;
|
||||||
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
||||||
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
||||||
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
||||||
@@ -151,6 +152,7 @@ public class BlockTransactionSelector {
|
|||||||
private List<AbstractTransactionSelector> createTransactionSelectors(
|
private List<AbstractTransactionSelector> createTransactionSelectors(
|
||||||
final BlockSelectionContext context) {
|
final BlockSelectionContext context) {
|
||||||
return List.of(
|
return List.of(
|
||||||
|
new SkipSenderTransactionSelector(context),
|
||||||
new BlockSizeTransactionSelector(context),
|
new BlockSizeTransactionSelector(context),
|
||||||
new BlobSizeTransactionSelector(context),
|
new BlobSizeTransactionSelector(context),
|
||||||
new PriceTransactionSelector(context),
|
new PriceTransactionSelector(context),
|
||||||
@@ -442,7 +444,8 @@ public class BlockTransactionSelector {
|
|||||||
evaluationContext, BLOCK_SELECTION_TIMEOUT, txWorldStateUpdater);
|
evaluationContext, BLOCK_SELECTION_TIMEOUT, txWorldStateUpdater);
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginTransactionSelector.onTransactionSelected(evaluationContext, processingResult);
|
notifySelected(evaluationContext, processingResult);
|
||||||
|
|
||||||
blockWorldStateUpdater = worldState.updater();
|
blockWorldStateUpdater = worldState.updater();
|
||||||
LOG.atTrace()
|
LOG.atTrace()
|
||||||
.setMessage("Selected {} for block creation, evaluated in {}")
|
.setMessage("Selected {} for block creation, evaluated in {}")
|
||||||
@@ -475,7 +478,7 @@ public class BlockTransactionSelector {
|
|||||||
: selectionResult;
|
: selectionResult;
|
||||||
|
|
||||||
transactionSelectionResults.updateNotSelected(evaluationContext.getTransaction(), actualResult);
|
transactionSelectionResults.updateNotSelected(evaluationContext.getTransaction(), actualResult);
|
||||||
pluginTransactionSelector.onTransactionNotSelected(evaluationContext, actualResult);
|
notifyNotSelected(evaluationContext, actualResult);
|
||||||
LOG.atTrace()
|
LOG.atTrace()
|
||||||
.setMessage(
|
.setMessage(
|
||||||
"Not selected {} for block creation with result {} (original result {}), evaluated in {}")
|
"Not selected {} for block creation with result {} (original result {}), evaluated in {}")
|
||||||
@@ -550,6 +553,26 @@ public class BlockTransactionSelector {
|
|||||||
return handleTransactionNotSelected(evaluationContext, selectionResult);
|
return handleTransactionNotSelected(evaluationContext, selectionResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifySelected(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionProcessingResult processingResult) {
|
||||||
|
|
||||||
|
for (var selector : transactionSelectors) {
|
||||||
|
selector.onTransactionSelected(evaluationContext, processingResult);
|
||||||
|
}
|
||||||
|
pluginTransactionSelector.onTransactionSelected(evaluationContext, processingResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyNotSelected(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionSelectionResult selectionResult) {
|
||||||
|
|
||||||
|
for (var selector : transactionSelectors) {
|
||||||
|
selector.onTransactionNotSelected(evaluationContext, selectionResult);
|
||||||
|
}
|
||||||
|
pluginTransactionSelector.onTransactionNotSelected(evaluationContext, selectionResult);
|
||||||
|
}
|
||||||
|
|
||||||
private void checkCancellation() {
|
private void checkCancellation() {
|
||||||
if (isCancelled.get()) {
|
if (isCancelled.get()) {
|
||||||
throw new CancellationException("Cancelled during transaction selection.");
|
throw new CancellationException("Cancelled during transaction selection.");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
|||||||
* transactions.
|
* transactions.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractTransactionSelector {
|
public abstract class AbstractTransactionSelector {
|
||||||
final BlockSelectionContext context;
|
protected final BlockSelectionContext context;
|
||||||
|
|
||||||
public AbstractTransactionSelector(final BlockSelectionContext context) {
|
public AbstractTransactionSelector(final BlockSelectionContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -55,4 +55,24 @@ public abstract class AbstractTransactionSelector {
|
|||||||
final TransactionEvaluationContext evaluationContext,
|
final TransactionEvaluationContext evaluationContext,
|
||||||
final TransactionSelectionResults blockTransactionResults,
|
final TransactionSelectionResults blockTransactionResults,
|
||||||
final TransactionProcessingResult processingResult);
|
final TransactionProcessingResult processingResult);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when a transaction is selected to be added to a block.
|
||||||
|
*
|
||||||
|
* @param evaluationContext The current selection context
|
||||||
|
* @param processingResult The result of processing the selected transaction.
|
||||||
|
*/
|
||||||
|
public void onTransactionSelected(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionProcessingResult processingResult) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when a transaction is not selected to be added to a block.
|
||||||
|
*
|
||||||
|
* @param evaluationContext The current selection context
|
||||||
|
* @param transactionSelectionResult The transaction selection result
|
||||||
|
*/
|
||||||
|
public void onTransactionNotSelected(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionSelectionResult transactionSelectionResult) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright contributors to 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.ethereum.blockcreation.txselection.selectors;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
|
||||||
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext;
|
||||||
|
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
|
||||||
|
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
|
||||||
|
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SkipSenderTransactionSelector extends AbstractTransactionSelector {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(SkipSenderTransactionSelector.class);
|
||||||
|
private final Set<Address> skippedSenders = new HashSet<>();
|
||||||
|
|
||||||
|
public SkipSenderTransactionSelector(final BlockSelectionContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionSelectionResults ignored) {
|
||||||
|
final var sender = evaluationContext.getTransaction().getSender();
|
||||||
|
if (skippedSenders.contains(sender)) {
|
||||||
|
LOG.atTrace()
|
||||||
|
.setMessage("Not selecting tx {} since its sender {} is in the skip list")
|
||||||
|
.addArgument(() -> evaluationContext.getPendingTransaction().toTraceLog())
|
||||||
|
.addArgument(sender)
|
||||||
|
.log();
|
||||||
|
|
||||||
|
return TransactionSelectionResult.SENDER_WITH_PREVIOUS_TX_NOT_SELECTED;
|
||||||
|
}
|
||||||
|
return TransactionSelectionResult.SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionSelectionResult evaluateTransactionPostProcessing(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionSelectionResults blockTransactionResults,
|
||||||
|
final TransactionProcessingResult processingResult) {
|
||||||
|
// All necessary checks were done in the pre-processing method, so nothing to do here.
|
||||||
|
return TransactionSelectionResult.SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a transaction is not selected we can skip processing any following transaction from the
|
||||||
|
* same sender, since it will never be selected due to the nonce gap, so we add the sender to the
|
||||||
|
* skip list.
|
||||||
|
*
|
||||||
|
* @param evaluationContext The current selection context
|
||||||
|
* @param transactionSelectionResult The transaction selection result
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onTransactionNotSelected(
|
||||||
|
final TransactionEvaluationContext evaluationContext,
|
||||||
|
final TransactionSelectionResult transactionSelectionResult) {
|
||||||
|
final var sender = evaluationContext.getTransaction().getSender();
|
||||||
|
skippedSenders.add(sender);
|
||||||
|
LOG.trace("Sender {} added to the skip list", sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,11 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.entry;
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
import static org.awaitility.Awaitility.await;
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER1;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER2;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER3;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER4;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER5;
|
||||||
import static org.hyperledger.besu.ethereum.core.MiningConfiguration.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
|
import static org.hyperledger.besu.ethereum.core.MiningConfiguration.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
|
||||||
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.EXECUTION_INTERRUPTED;
|
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.EXECUTION_INTERRUPTED;
|
||||||
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.NONCE_TOO_LOW;
|
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.NONCE_TOO_LOW;
|
||||||
@@ -62,7 +67,6 @@ import org.hyperledger.besu.ethereum.core.MiningConfiguration;
|
|||||||
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
||||||
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
|
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
|
||||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||||
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
|
|
||||||
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
|
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
|
||||||
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
|
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
|
||||||
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
|
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
|
||||||
@@ -80,7 +84,6 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.provider.WorldStateQu
|
|||||||
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
|
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
|
||||||
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
|
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
|
||||||
import org.hyperledger.besu.evm.internal.EvmConfiguration;
|
import org.hyperledger.besu.evm.internal.EvmConfiguration;
|
||||||
import org.hyperledger.besu.evm.worldstate.WorldState;
|
|
||||||
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
|
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
|
||||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||||
import org.hyperledger.besu.plugin.services.MetricsSystem;
|
import org.hyperledger.besu.plugin.services.MetricsSystem;
|
||||||
@@ -127,10 +130,6 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
protected static final double MIN_OCCUPANCY_80_PERCENT = 0.8;
|
protected static final double MIN_OCCUPANCY_80_PERCENT = 0.8;
|
||||||
protected static final double MIN_OCCUPANCY_100_PERCENT = 1;
|
protected static final double MIN_OCCUPANCY_100_PERCENT = 1;
|
||||||
protected static final BigInteger CHAIN_ID = BigInteger.valueOf(42L);
|
protected static final BigInteger CHAIN_ID = BigInteger.valueOf(42L);
|
||||||
protected static final KeyPair keyPair =
|
|
||||||
SignatureAlgorithmFactory.getInstance().generateKeyPair();
|
|
||||||
protected static final Address sender =
|
|
||||||
Address.extract(Hash.hash(keyPair.getPublicKey().getEncodedBytes()));
|
|
||||||
|
|
||||||
protected final MetricsSystem metricsSystem = new NoOpMetricsSystem();
|
protected final MetricsSystem metricsSystem = new NoOpMetricsSystem();
|
||||||
protected GenesisConfig genesisConfig;
|
protected GenesisConfig genesisConfig;
|
||||||
@@ -180,7 +179,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
|
|
||||||
worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState();
|
worldState = InMemoryKeyValueStorageProvider.createInMemoryWorldState();
|
||||||
final var worldStateUpdater = worldState.updater();
|
final var worldStateUpdater = worldState.updater();
|
||||||
worldStateUpdater.createAccount(sender, 0, Wei.of(1_000_000_000L));
|
Arrays.stream(Sender.values())
|
||||||
|
.map(Sender::address)
|
||||||
|
.forEach(address -> worldStateUpdater.createAccount(address, 0, Wei.of(1_000_000_000L)));
|
||||||
worldStateUpdater.commit();
|
worldStateUpdater.commit();
|
||||||
|
|
||||||
when(protocolContext.getWorldStateArchive().getWorldState(any(WorldStateQueryParams.class)))
|
when(protocolContext.getWorldStateArchive().getWorldState(any(WorldStateQueryParams.class)))
|
||||||
@@ -303,9 +304,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
Wei.ZERO,
|
Wei.ZERO,
|
||||||
transactionSelectionService);
|
transactionSelectionService);
|
||||||
|
|
||||||
final List<Transaction> transactionsToInject = Lists.newArrayList();
|
final List<Transaction> transactionsToInject = new ArrayList<>(5);
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
final Transaction tx = createTransaction(i, Wei.of(7), 100_000);
|
final Transaction tx = createTransaction(i, Wei.of(7), 100_000, Sender.values()[i]);
|
||||||
transactionsToInject.add(tx);
|
transactionsToInject.add(tx);
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
ensureTransactionIsInvalid(tx, TransactionInvalidReason.NONCE_TOO_LOW);
|
ensureTransactionIsInvalid(tx, TransactionInvalidReason.NONCE_TOO_LOW);
|
||||||
@@ -389,9 +390,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
// NOTE - PendingTransactions outputs these in nonce order
|
// NOTE - PendingTransactions outputs these in nonce order
|
||||||
final Transaction[] txs =
|
final Transaction[] txs =
|
||||||
new Transaction[] {
|
new Transaction[] {
|
||||||
createTransaction(1, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79)),
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79), SENDER1),
|
||||||
createTransaction(2, Wei.of(10), blockHeader.getGasLimit()),
|
createTransaction(0, Wei.of(10), blockHeader.getGasLimit(), SENDER2),
|
||||||
createTransaction(3, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1))
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1), SENDER3)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (final Transaction tx : txs) {
|
for (final Transaction tx : txs) {
|
||||||
@@ -425,10 +426,10 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
// NOTE - PendingTransactions will output these in nonce order.
|
// NOTE - PendingTransactions will output these in nonce order.
|
||||||
final Transaction[] txs =
|
final Transaction[] txs =
|
||||||
new Transaction[] {
|
new Transaction[] {
|
||||||
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.15)),
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.15), SENDER1),
|
||||||
createTransaction(1, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79)),
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.79), SENDER2),
|
||||||
createTransaction(2, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.25)),
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.25), SENDER3),
|
||||||
createTransaction(3, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1))
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1), SENDER4)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (Transaction tx : txs) {
|
for (Transaction tx : txs) {
|
||||||
@@ -443,6 +444,44 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
.containsOnly(entry(txs[2], TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD));
|
.containsOnly(entry(txs[2], TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ifATransactionIsNotSelectedFollowingOnesFromTheSameSenderAreSkipped() {
|
||||||
|
final ProcessableBlockHeader blockHeader = createBlock(300_000);
|
||||||
|
final Address miningBeneficiary = AddressHelpers.ofValue(1);
|
||||||
|
final BlockTransactionSelector selector =
|
||||||
|
createBlockSelectorAndSetupTxPool(
|
||||||
|
defaultTestMiningConfiguration,
|
||||||
|
transactionProcessor,
|
||||||
|
blockHeader,
|
||||||
|
miningBeneficiary,
|
||||||
|
Wei.ZERO,
|
||||||
|
transactionSelectionService);
|
||||||
|
|
||||||
|
// Add 3 transactions from the same sender to the Pending Transactions
|
||||||
|
// first is selected
|
||||||
|
// second id not selected
|
||||||
|
// third is skipped, not processed, since cannot be selected due to the nonce gap
|
||||||
|
final Transaction[] txs =
|
||||||
|
new Transaction[] {
|
||||||
|
createTransaction(0, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.5), SENDER1),
|
||||||
|
createTransaction(1, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.6), SENDER1),
|
||||||
|
createTransaction(2, Wei.of(10), (long) (blockHeader.getGasLimit() * 0.1), SENDER1)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Transaction tx : txs) {
|
||||||
|
ensureTransactionIsValid(tx);
|
||||||
|
}
|
||||||
|
transactionPool.addRemoteTransactions(Arrays.stream(txs).toList());
|
||||||
|
|
||||||
|
final TransactionSelectionResults results = selector.buildTransactionListForBlock();
|
||||||
|
|
||||||
|
assertThat(results.getSelectedTransactions()).containsExactly(txs[0]);
|
||||||
|
assertThat(results.getNotSelectedTransactions())
|
||||||
|
.containsOnly(
|
||||||
|
entry(txs[1], TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS),
|
||||||
|
entry(txs[2], TransactionSelectionResult.SENDER_WITH_PREVIOUS_TX_NOT_SELECTED));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transactionSelectionStopsWhenBlockIsFull() {
|
public void transactionSelectionStopsWhenBlockIsFull() {
|
||||||
final ProcessableBlockHeader blockHeader = createBlock(3_000_000);
|
final ProcessableBlockHeader blockHeader = createBlock(3_000_000);
|
||||||
@@ -471,18 +510,18 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
// 4) min gas cost (not selected since selection stopped after tx 3)
|
// 4) min gas cost (not selected since selection stopped after tx 3)
|
||||||
// NOTE - PendingTransactions outputs these in nonce order
|
// NOTE - PendingTransactions outputs these in nonce order
|
||||||
|
|
||||||
final long gasLimit0 = (long) (blockHeader.getGasLimit() * 0.9);
|
final long gasLimit0s1 = (long) (blockHeader.getGasLimit() * 0.9);
|
||||||
final long gasLimit1 = (long) (blockHeader.getGasLimit() * 0.9);
|
final long gasLimit1s1 = (long) (blockHeader.getGasLimit() * 0.9);
|
||||||
final long gasLimit2 = blockHeader.getGasLimit() - gasLimit0 - minTxGasCost;
|
final long gasLimit0s2 = blockHeader.getGasLimit() - gasLimit0s1 - minTxGasCost;
|
||||||
final long gasLimit3 = minTxGasCost;
|
final long gasLimit1s2 = minTxGasCost;
|
||||||
final long gasLimit4 = minTxGasCost;
|
final long gasLimit2s2 = minTxGasCost;
|
||||||
|
|
||||||
final List<Transaction> transactionsToInject = Lists.newArrayList();
|
final List<Transaction> transactionsToInject = Lists.newArrayList();
|
||||||
transactionsToInject.add(createTransaction(0, Wei.of(7), gasLimit0));
|
transactionsToInject.add(createTransaction(0, Wei.of(7), gasLimit0s1, SENDER1));
|
||||||
transactionsToInject.add(createTransaction(1, Wei.of(7), gasLimit1));
|
transactionsToInject.add(createTransaction(1, Wei.of(7), gasLimit1s1, SENDER1));
|
||||||
transactionsToInject.add(createTransaction(2, Wei.of(7), gasLimit2));
|
transactionsToInject.add(createTransaction(0, Wei.of(7), gasLimit0s2, SENDER2));
|
||||||
transactionsToInject.add(createTransaction(3, Wei.of(7), gasLimit3));
|
transactionsToInject.add(createTransaction(1, Wei.of(7), gasLimit1s2, SENDER2));
|
||||||
transactionsToInject.add(createTransaction(4, Wei.of(7), gasLimit4));
|
transactionsToInject.add(createTransaction(2, Wei.of(7), gasLimit2s2, SENDER2));
|
||||||
|
|
||||||
for (final Transaction tx : transactionsToInject) {
|
for (final Transaction tx : transactionsToInject) {
|
||||||
ensureTransactionIsValid(tx);
|
ensureTransactionIsValid(tx);
|
||||||
@@ -532,16 +571,16 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
// 3) min gas cost (skipped since not enough gas remaining)
|
// 3) min gas cost (skipped since not enough gas remaining)
|
||||||
// NOTE - PendingTransactions outputs these in nonce order
|
// NOTE - PendingTransactions outputs these in nonce order
|
||||||
|
|
||||||
final long gasLimit0 = (long) (blockHeader.getGasLimit() * 0.9);
|
final long gasLimit0s1 = (long) (blockHeader.getGasLimit() * 0.9);
|
||||||
final long gasLimit1 = (long) (blockHeader.getGasLimit() * 0.9);
|
final long gasLimit1s1 = (long) (blockHeader.getGasLimit() * 0.9);
|
||||||
final long gasLimit2 = blockHeader.getGasLimit() - gasLimit0 - (minTxGasCost - 1);
|
final long gasLimit0s2 = blockHeader.getGasLimit() - gasLimit0s1 - (minTxGasCost - 1);
|
||||||
final long gasLimit3 = minTxGasCost;
|
final long gasLimit1s2 = minTxGasCost;
|
||||||
|
|
||||||
final List<Transaction> transactionsToInject = Lists.newArrayList();
|
final List<Transaction> transactionsToInject = new ArrayList<>(4);
|
||||||
transactionsToInject.add(createTransaction(0, Wei.of(10), gasLimit0));
|
transactionsToInject.add(createTransaction(0, Wei.of(10), gasLimit0s1, SENDER1));
|
||||||
transactionsToInject.add(createTransaction(1, Wei.of(10), gasLimit1));
|
transactionsToInject.add(createTransaction(1, Wei.of(10), gasLimit1s1, SENDER1));
|
||||||
transactionsToInject.add(createTransaction(2, Wei.of(10), gasLimit2));
|
transactionsToInject.add(createTransaction(0, Wei.of(10), gasLimit0s2, SENDER2));
|
||||||
transactionsToInject.add(createTransaction(3, Wei.of(10), gasLimit3));
|
transactionsToInject.add(createTransaction(1, Wei.of(10), gasLimit1s2, SENDER2));
|
||||||
|
|
||||||
for (final Transaction tx : transactionsToInject) {
|
for (final Transaction tx : transactionsToInject) {
|
||||||
ensureTransactionIsValid(tx);
|
ensureTransactionIsValid(tx);
|
||||||
@@ -600,13 +639,13 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
final ProcessableBlockHeader blockHeader = createBlock(300_000);
|
final ProcessableBlockHeader blockHeader = createBlock(300_000);
|
||||||
final Address miningBeneficiary = AddressHelpers.ofValue(1);
|
final Address miningBeneficiary = AddressHelpers.ofValue(1);
|
||||||
|
|
||||||
final Transaction selected = createTransaction(0, Wei.of(10), 21_000);
|
final Transaction selected = createTransaction(0, Wei.of(10), 21_000, SENDER1);
|
||||||
ensureTransactionIsValid(selected, 21_000, 0);
|
ensureTransactionIsValid(selected, 21_000, 0);
|
||||||
|
|
||||||
final Transaction notSelectedTransient = createTransaction(1, Wei.of(10), 21_000);
|
final Transaction notSelectedTransient = createTransaction(1, Wei.of(10), 21_000, SENDER1);
|
||||||
ensureTransactionIsValid(notSelectedTransient, 21_000, 0);
|
ensureTransactionIsValid(notSelectedTransient, 21_000, 0);
|
||||||
|
|
||||||
final Transaction notSelectedInvalid = createTransaction(2, Wei.of(10), 21_000);
|
final Transaction notSelectedInvalid = createTransaction(2, Wei.of(10), 21_000, SENDER2);
|
||||||
ensureTransactionIsValid(notSelectedInvalid, 21_000, 0);
|
ensureTransactionIsValid(notSelectedInvalid, 21_000, 0);
|
||||||
|
|
||||||
final PluginTransactionSelectorFactory transactionSelectorFactory =
|
final PluginTransactionSelectorFactory transactionSelectorFactory =
|
||||||
@@ -723,12 +762,12 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
Wei.ZERO,
|
Wei.ZERO,
|
||||||
transactionSelectionService);
|
transactionSelectionService);
|
||||||
|
|
||||||
transactionPool.addRemoteTransactions(List.of(selected, notSelected, selected3));
|
transactionPool.addRemoteTransactions(List.of(selected, notSelected));
|
||||||
|
|
||||||
final TransactionSelectionResults transactionSelectionResults =
|
final TransactionSelectionResults transactionSelectionResults =
|
||||||
selector.buildTransactionListForBlock();
|
selector.buildTransactionListForBlock();
|
||||||
|
|
||||||
assertThat(transactionSelectionResults.getSelectedTransactions()).contains(selected, selected3);
|
assertThat(transactionSelectionResults.getSelectedTransactions()).contains(selected);
|
||||||
assertThat(transactionSelectionResults.getNotSelectedTransactions())
|
assertThat(transactionSelectionResults.getNotSelectedTransactions())
|
||||||
.containsOnly(
|
.containsOnly(
|
||||||
entry(notSelected, PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT));
|
entry(notSelected, PluginTransactionSelectionResult.GENERIC_PLUGIN_INVALID_TRANSIENT));
|
||||||
@@ -1170,7 +1209,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
|
|
||||||
final List<Transaction> transactionsToInject = new ArrayList<>(txCount);
|
final List<Transaction> transactionsToInject = new ArrayList<>(txCount);
|
||||||
for (int i = 0; i < txCount - 1; i++) {
|
for (int i = 0; i < txCount - 1; i++) {
|
||||||
final Transaction tx = createTransaction(i, Wei.of(7), 100_000);
|
final Transaction tx = createTransaction(0, Wei.of(7), 100_000, Sender.values()[i]);
|
||||||
transactionsToInject.add(tx);
|
transactionsToInject.add(tx);
|
||||||
if (processingTooLate) {
|
if (processingTooLate) {
|
||||||
ensureTransactionIsInvalid(tx, txInvalidReason, fastProcessingTxTime);
|
ensureTransactionIsInvalid(tx, txInvalidReason, fastProcessingTxTime);
|
||||||
@@ -1179,7 +1218,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Transaction lateTx = createTransaction(2, Wei.of(7), 100_000);
|
final Transaction lateTx = createTransaction(0, Wei.of(7), 100_000, SENDER5);
|
||||||
transactionsToInject.add(lateTx);
|
transactionsToInject.add(lateTx);
|
||||||
if (processingTooLate) {
|
if (processingTooLate) {
|
||||||
ensureTransactionIsInvalid(lateTx, txInvalidReason, longProcessingTxTime);
|
ensureTransactionIsInvalid(lateTx, txInvalidReason, longProcessingTxTime);
|
||||||
@@ -1293,7 +1332,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
worldState,
|
worldState,
|
||||||
transactionPool,
|
transactionPool,
|
||||||
blockHeader,
|
blockHeader,
|
||||||
this::createReceipt,
|
protocolSchedule.getByBlockHeader(blockHeader).getTransactionReceiptFactory(),
|
||||||
this::isCancelled,
|
this::isCancelled,
|
||||||
miningBeneficiary,
|
miningBeneficiary,
|
||||||
blobGasPrice,
|
blobGasPrice,
|
||||||
@@ -1317,6 +1356,11 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
|
|
||||||
protected Transaction createTransaction(
|
protected Transaction createTransaction(
|
||||||
final int nonce, final Wei gasPrice, final long gasLimit) {
|
final int nonce, final Wei gasPrice, final long gasLimit) {
|
||||||
|
return createTransaction(nonce, gasPrice, gasLimit, SENDER1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Transaction createTransaction(
|
||||||
|
final int nonce, final Wei gasPrice, final long gasLimit, final Sender sender) {
|
||||||
return Transaction.builder()
|
return Transaction.builder()
|
||||||
.gasLimit(gasLimit)
|
.gasLimit(gasLimit)
|
||||||
.gasPrice(gasPrice)
|
.gasPrice(gasPrice)
|
||||||
@@ -1324,10 +1368,10 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
.payload(Bytes.EMPTY)
|
.payload(Bytes.EMPTY)
|
||||||
.to(Address.ID)
|
.to(Address.ID)
|
||||||
.value(Wei.of(nonce))
|
.value(Wei.of(nonce))
|
||||||
.sender(sender)
|
.sender(sender.address())
|
||||||
.chainId(CHAIN_ID)
|
.chainId(CHAIN_ID)
|
||||||
.guessType()
|
.guessType()
|
||||||
.signAndBuild(keyPair);
|
.signAndBuild(sender.keyPair());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transaction createEIP1559Transaction(
|
protected Transaction createEIP1559Transaction(
|
||||||
@@ -1335,6 +1379,15 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
final Wei maxFeePerGas,
|
final Wei maxFeePerGas,
|
||||||
final Wei maxPriorityFeePerGas,
|
final Wei maxPriorityFeePerGas,
|
||||||
final long gasLimit) {
|
final long gasLimit) {
|
||||||
|
return createEIP1559Transaction(nonce, maxFeePerGas, maxPriorityFeePerGas, gasLimit, SENDER1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Transaction createEIP1559Transaction(
|
||||||
|
final int nonce,
|
||||||
|
final Wei maxFeePerGas,
|
||||||
|
final Wei maxPriorityFeePerGas,
|
||||||
|
final long gasLimit,
|
||||||
|
final Sender sender) {
|
||||||
return Transaction.builder()
|
return Transaction.builder()
|
||||||
.type(TransactionType.EIP1559)
|
.type(TransactionType.EIP1559)
|
||||||
.gasLimit(gasLimit)
|
.gasLimit(gasLimit)
|
||||||
@@ -1344,19 +1397,9 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
.payload(Bytes.EMPTY)
|
.payload(Bytes.EMPTY)
|
||||||
.to(Address.ID)
|
.to(Address.ID)
|
||||||
.value(Wei.of(nonce))
|
.value(Wei.of(nonce))
|
||||||
.sender(sender)
|
.sender(sender.address())
|
||||||
.chainId(CHAIN_ID)
|
.chainId(CHAIN_ID)
|
||||||
.signAndBuild(keyPair);
|
.signAndBuild(sender.keyPair());
|
||||||
}
|
|
||||||
|
|
||||||
// This is a duplicate of the MainnetProtocolSpec::frontierTransactionReceiptFactory
|
|
||||||
private TransactionReceipt createReceipt(
|
|
||||||
final TransactionType __,
|
|
||||||
final TransactionProcessingResult result,
|
|
||||||
final WorldState worldState,
|
|
||||||
final long gasUsed) {
|
|
||||||
return new TransactionReceipt(
|
|
||||||
worldState.rootHash(), gasUsed, Lists.newArrayList(), Optional.empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ensureTransactionIsValid(final Transaction tx) {
|
protected void ensureTransactionIsValid(final Transaction tx) {
|
||||||
@@ -1507,4 +1550,34 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
|||||||
return new PluginTransactionSelectionResult(PluginStatus.PLUGIN_INVALID, invalidReason);
|
return new PluginTransactionSelectionResult(PluginStatus.PLUGIN_INVALID, invalidReason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected enum Sender {
|
||||||
|
// it is important to keep the addresses of the senders sorted, to make the tests reproducible,
|
||||||
|
// since a different sender address can change the order in which txs are selected,
|
||||||
|
// if all the other sorting fields are equal
|
||||||
|
SENDER1(4), // 0x1eff47bc3a10a45d4b230b5d10e37751fe6aa718
|
||||||
|
SENDER2(2), // 0x2b5ad5c4795c026514f8317c7a215e218dccd6cf
|
||||||
|
SENDER3(3), // 0x6813eb9362372eef6200f3b1dbc3f819671cba69
|
||||||
|
SENDER4(1), // 0x7e5f4552091a69125d5dfcb7b8c2659029395bdf
|
||||||
|
SENDER5(5); // 0xe1ab8145f7e55dc933d51a18c793f901a3a0b276
|
||||||
|
|
||||||
|
private final KeyPair keyPair;
|
||||||
|
private final Address address;
|
||||||
|
|
||||||
|
Sender(final int seed) {
|
||||||
|
final var privateKey =
|
||||||
|
SignatureAlgorithmFactory.getInstance().createPrivateKey(BigInteger.valueOf(seed));
|
||||||
|
final var publicKey = SignatureAlgorithmFactory.getInstance().createPublicKey(privateKey);
|
||||||
|
this.keyPair = new KeyPair(privateKey, publicKey);
|
||||||
|
this.address = Address.extract(Hash.hash(publicKey.getEncodedBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyPair keyPair() {
|
||||||
|
return keyPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address address() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ package org.hyperledger.besu.ethereum.blockcreation;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.entry;
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER1;
|
||||||
|
import static org.hyperledger.besu.ethereum.blockcreation.AbstractBlockTransactionSelectorTest.Sender.SENDER2;
|
||||||
import static org.hyperledger.besu.ethereum.core.MiningConfiguration.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
|
import static org.hyperledger.besu.ethereum.core.MiningConfiguration.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
@@ -246,19 +248,23 @@ public class LondonFeeMarketBlockTransactionSelectorTest
|
|||||||
ImmutableMiningConfiguration.builder().from(defaultTestMiningConfiguration).build();
|
ImmutableMiningConfiguration.builder().from(defaultTestMiningConfiguration).build();
|
||||||
miningConfiguration.setMinPriorityFeePerGas(Wei.of(7));
|
miningConfiguration.setMinPriorityFeePerGas(Wei.of(7));
|
||||||
|
|
||||||
final Transaction txSelected1 = createEIP1559Transaction(1, Wei.of(8), Wei.of(8), 100_000);
|
final Transaction txSelected1 =
|
||||||
|
createEIP1559Transaction(0, Wei.of(8), Wei.of(8), 100_000, SENDER1);
|
||||||
ensureTransactionIsValid(txSelected1);
|
ensureTransactionIsValid(txSelected1);
|
||||||
|
|
||||||
// transaction txNotSelected1 should not be selected
|
// transaction txNotSelected1 should not be selected
|
||||||
final Transaction txNotSelected1 = createEIP1559Transaction(2, Wei.of(7), Wei.of(7), 100_000);
|
final Transaction txNotSelected1 =
|
||||||
|
createEIP1559Transaction(1, Wei.of(7), Wei.of(7), 100_000, SENDER1);
|
||||||
ensureTransactionIsValid(txNotSelected1);
|
ensureTransactionIsValid(txNotSelected1);
|
||||||
|
|
||||||
// transaction txSelected2 should be selected
|
// transaction txSelected2 should be selected
|
||||||
final Transaction txSelected2 = createEIP1559Transaction(3, Wei.of(8), Wei.of(8), 100_000);
|
final Transaction txSelected2 =
|
||||||
|
createEIP1559Transaction(0, Wei.of(8), Wei.of(8), 100_000, SENDER2);
|
||||||
ensureTransactionIsValid(txSelected2);
|
ensureTransactionIsValid(txSelected2);
|
||||||
|
|
||||||
// transaction txNotSelected2 should not be selected
|
// transaction txNotSelected2 should not be selected
|
||||||
final Transaction txNotSelected2 = createEIP1559Transaction(4, Wei.of(8), Wei.of(6), 100_000);
|
final Transaction txNotSelected2 =
|
||||||
|
createEIP1559Transaction(1, Wei.of(8), Wei.of(6), 100_000, SENDER2);
|
||||||
ensureTransactionIsValid(txNotSelected2);
|
ensureTransactionIsValid(txNotSelected2);
|
||||||
|
|
||||||
final BlockTransactionSelector selector =
|
final BlockTransactionSelector selector =
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class BlockProcessingResult extends BlockValidationResult {
|
|||||||
|
|
||||||
private final Optional<BlockProcessingOutputs> yield;
|
private final Optional<BlockProcessingOutputs> yield;
|
||||||
private final boolean isPartial;
|
private final boolean isPartial;
|
||||||
private Optional<Integer> nbParallelizedTransations = Optional.empty();
|
private Optional<Integer> nbParallelizedTransactions = Optional.empty();
|
||||||
|
|
||||||
/** A result indicating that processing failed. */
|
/** A result indicating that processing failed. */
|
||||||
public static final BlockProcessingResult FAILED = new BlockProcessingResult("processing failed");
|
public static final BlockProcessingResult FAILED = new BlockProcessingResult("processing failed");
|
||||||
@@ -45,15 +45,15 @@ public class BlockProcessingResult extends BlockValidationResult {
|
|||||||
* A result indicating that processing was successful but incomplete.
|
* A result indicating that processing was successful but incomplete.
|
||||||
*
|
*
|
||||||
* @param yield the outputs of processing a block
|
* @param yield the outputs of processing a block
|
||||||
* @param nbParallelizedTransations potential number of parallelized transactions during block
|
* @param nbParallelizedTransactions potential number of parallelized transactions during block
|
||||||
* processing
|
* processing
|
||||||
*/
|
*/
|
||||||
public BlockProcessingResult(
|
public BlockProcessingResult(
|
||||||
final Optional<BlockProcessingOutputs> yield,
|
final Optional<BlockProcessingOutputs> yield,
|
||||||
final Optional<Integer> nbParallelizedTransations) {
|
final Optional<Integer> nbParallelizedTransactions) {
|
||||||
this.yield = yield;
|
this.yield = yield;
|
||||||
this.isPartial = false;
|
this.isPartial = false;
|
||||||
this.nbParallelizedTransations = nbParallelizedTransations;
|
this.nbParallelizedTransactions = nbParallelizedTransactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,7 +166,7 @@ public class BlockProcessingResult extends BlockValidationResult {
|
|||||||
*
|
*
|
||||||
* @return Optional of parallelized transactions during the block execution
|
* @return Optional of parallelized transactions during the block execution
|
||||||
*/
|
*/
|
||||||
public Optional<Integer> getNbParallelizedTransations() {
|
public Optional<Integer> getNbParallelizedTransactions() {
|
||||||
return nbParallelizedTransations;
|
return nbParallelizedTransactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public class MainnetBlockValidator implements BlockValidator {
|
|||||||
|
|
||||||
return new BlockProcessingResult(
|
return new BlockProcessingResult(
|
||||||
Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests)),
|
Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests)),
|
||||||
result.getNbParallelizedTransations());
|
result.getNbParallelizedTransactions());
|
||||||
}
|
}
|
||||||
} catch (MerkleTrieException ex) {
|
} catch (MerkleTrieException ex) {
|
||||||
context.getWorldStateArchive().heal(ex.getMaybeAddress(), ex.getLocation());
|
context.getWorldStateArchive().heal(ex.getMaybeAddress(), ex.getLocation());
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPOutput;
|
|||||||
import org.hyperledger.besu.evm.log.LogsBloomFilter;
|
import org.hyperledger.besu.evm.log.LogsBloomFilter;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
@@ -43,6 +44,8 @@ public class BlockHeader extends SealableBlockHeader
|
|||||||
|
|
||||||
private final Supplier<ParsedExtraData> parsedExtraData;
|
private final Supplier<ParsedExtraData> parsedExtraData;
|
||||||
|
|
||||||
|
private final Optional<Bytes> rawRlp;
|
||||||
|
|
||||||
public BlockHeader(
|
public BlockHeader(
|
||||||
final Hash parentHash,
|
final Hash parentHash,
|
||||||
final Hash ommersHash,
|
final Hash ommersHash,
|
||||||
@@ -66,6 +69,56 @@ public class BlockHeader extends SealableBlockHeader
|
|||||||
final Bytes32 parentBeaconBlockRoot,
|
final Bytes32 parentBeaconBlockRoot,
|
||||||
final Hash requestsHash,
|
final Hash requestsHash,
|
||||||
final BlockHeaderFunctions blockHeaderFunctions) {
|
final BlockHeaderFunctions blockHeaderFunctions) {
|
||||||
|
this(
|
||||||
|
parentHash,
|
||||||
|
ommersHash,
|
||||||
|
coinbase,
|
||||||
|
stateRoot,
|
||||||
|
transactionsRoot,
|
||||||
|
receiptsRoot,
|
||||||
|
logsBloom,
|
||||||
|
difficulty,
|
||||||
|
number,
|
||||||
|
gasLimit,
|
||||||
|
gasUsed,
|
||||||
|
timestamp,
|
||||||
|
extraData,
|
||||||
|
baseFee,
|
||||||
|
mixHashOrPrevRandao,
|
||||||
|
nonce,
|
||||||
|
withdrawalsRoot,
|
||||||
|
blobGasUsed,
|
||||||
|
excessBlobGas,
|
||||||
|
parentBeaconBlockRoot,
|
||||||
|
requestsHash,
|
||||||
|
blockHeaderFunctions,
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockHeader(
|
||||||
|
final Hash parentHash,
|
||||||
|
final Hash ommersHash,
|
||||||
|
final Address coinbase,
|
||||||
|
final Hash stateRoot,
|
||||||
|
final Hash transactionsRoot,
|
||||||
|
final Hash receiptsRoot,
|
||||||
|
final LogsBloomFilter logsBloom,
|
||||||
|
final Difficulty difficulty,
|
||||||
|
final long number,
|
||||||
|
final long gasLimit,
|
||||||
|
final long gasUsed,
|
||||||
|
final long timestamp,
|
||||||
|
final Bytes extraData,
|
||||||
|
final Wei baseFee,
|
||||||
|
final Bytes32 mixHashOrPrevRandao,
|
||||||
|
final long nonce,
|
||||||
|
final Hash withdrawalsRoot,
|
||||||
|
final Long blobGasUsed,
|
||||||
|
final BlobGas excessBlobGas,
|
||||||
|
final Bytes32 parentBeaconBlockRoot,
|
||||||
|
final Hash requestsHash,
|
||||||
|
final BlockHeaderFunctions blockHeaderFunctions,
|
||||||
|
final Optional<Bytes> rawRlp) {
|
||||||
super(
|
super(
|
||||||
parentHash,
|
parentHash,
|
||||||
ommersHash,
|
ommersHash,
|
||||||
@@ -90,6 +143,7 @@ public class BlockHeader extends SealableBlockHeader
|
|||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this));
|
this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this));
|
||||||
this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this));
|
this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this));
|
||||||
|
this.rawRlp = rawRlp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasEmptyBlock(final BlockHeader blockHeader) {
|
public static boolean hasEmptyBlock(final BlockHeader blockHeader) {
|
||||||
@@ -154,72 +208,80 @@ public class BlockHeader extends SealableBlockHeader
|
|||||||
* @param out The RLP output to write to
|
* @param out The RLP output to write to
|
||||||
*/
|
*/
|
||||||
public void writeTo(final RLPOutput out) {
|
public void writeTo(final RLPOutput out) {
|
||||||
out.startList();
|
rawRlp.ifPresentOrElse(
|
||||||
|
out::writeRLPBytes,
|
||||||
|
() -> {
|
||||||
|
out.startList();
|
||||||
|
|
||||||
out.writeBytes(parentHash);
|
out.writeBytes(parentHash);
|
||||||
out.writeBytes(ommersHash);
|
out.writeBytes(ommersHash);
|
||||||
out.writeBytes(coinbase);
|
out.writeBytes(coinbase);
|
||||||
out.writeBytes(stateRoot);
|
out.writeBytes(stateRoot);
|
||||||
out.writeBytes(transactionsRoot);
|
out.writeBytes(transactionsRoot);
|
||||||
out.writeBytes(receiptsRoot);
|
out.writeBytes(receiptsRoot);
|
||||||
out.writeBytes(logsBloom);
|
out.writeBytes(logsBloom);
|
||||||
out.writeUInt256Scalar(difficulty);
|
out.writeUInt256Scalar(difficulty);
|
||||||
out.writeLongScalar(number);
|
out.writeLongScalar(number);
|
||||||
out.writeLongScalar(gasLimit);
|
out.writeLongScalar(gasLimit);
|
||||||
out.writeLongScalar(gasUsed);
|
out.writeLongScalar(gasUsed);
|
||||||
out.writeLongScalar(timestamp);
|
out.writeLongScalar(timestamp);
|
||||||
out.writeBytes(extraData);
|
out.writeBytes(extraData);
|
||||||
out.writeBytes(mixHashOrPrevRandao);
|
out.writeBytes(mixHashOrPrevRandao);
|
||||||
out.writeLong(nonce);
|
out.writeLong(nonce);
|
||||||
do {
|
do {
|
||||||
if (baseFee == null) break;
|
if (baseFee == null) break;
|
||||||
out.writeUInt256Scalar(baseFee);
|
out.writeUInt256Scalar(baseFee);
|
||||||
|
|
||||||
if (withdrawalsRoot == null) break;
|
if (withdrawalsRoot == null) break;
|
||||||
out.writeBytes(withdrawalsRoot);
|
out.writeBytes(withdrawalsRoot);
|
||||||
|
|
||||||
if (excessBlobGas == null || blobGasUsed == null) break;
|
if (excessBlobGas == null || blobGasUsed == null) break;
|
||||||
out.writeLongScalar(blobGasUsed);
|
out.writeLongScalar(blobGasUsed);
|
||||||
out.writeUInt64Scalar(excessBlobGas);
|
out.writeUInt64Scalar(excessBlobGas);
|
||||||
|
|
||||||
if (parentBeaconBlockRoot == null) break;
|
if (parentBeaconBlockRoot == null) break;
|
||||||
out.writeBytes(parentBeaconBlockRoot);
|
out.writeBytes(parentBeaconBlockRoot);
|
||||||
|
|
||||||
if (requestsHash == null) break;
|
if (requestsHash == null) break;
|
||||||
out.writeBytes(requestsHash);
|
out.writeBytes(requestsHash);
|
||||||
} while (false);
|
} while (false);
|
||||||
out.endList();
|
out.endList();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockHeader readFrom(
|
public static BlockHeader readFrom(
|
||||||
final RLPInput input, final BlockHeaderFunctions blockHeaderFunctions) {
|
final RLPInput input, final BlockHeaderFunctions blockHeaderFunctions) {
|
||||||
input.enterList();
|
final RLPInput headerRlp = input.readAsRlp();
|
||||||
final Hash parentHash = Hash.wrap(input.readBytes32());
|
headerRlp.enterList();
|
||||||
final Hash ommersHash = Hash.wrap(input.readBytes32());
|
final Hash parentHash = Hash.wrap(headerRlp.readBytes32());
|
||||||
final Address coinbase = Address.readFrom(input);
|
final Hash ommersHash = Hash.wrap(headerRlp.readBytes32());
|
||||||
final Hash stateRoot = Hash.wrap(input.readBytes32());
|
final Address coinbase = Address.readFrom(headerRlp);
|
||||||
final Hash transactionsRoot = Hash.wrap(input.readBytes32());
|
final Hash stateRoot = Hash.wrap(headerRlp.readBytes32());
|
||||||
final Hash receiptsRoot = Hash.wrap(input.readBytes32());
|
final Hash transactionsRoot = Hash.wrap(headerRlp.readBytes32());
|
||||||
final LogsBloomFilter logsBloom = LogsBloomFilter.readFrom(input);
|
final Hash receiptsRoot = Hash.wrap(headerRlp.readBytes32());
|
||||||
final Difficulty difficulty = Difficulty.of(input.readUInt256Scalar());
|
final LogsBloomFilter logsBloom = LogsBloomFilter.readFrom(headerRlp);
|
||||||
final long number = input.readLongScalar();
|
final Difficulty difficulty = Difficulty.of(headerRlp.readUInt256Scalar());
|
||||||
final long gasLimit = input.readLongScalar();
|
final long number = headerRlp.readLongScalar();
|
||||||
final long gasUsed = input.readLongScalar();
|
final long gasLimit = headerRlp.readLongScalar();
|
||||||
final long timestamp = input.readLongScalar();
|
final long gasUsed = headerRlp.readLongScalar();
|
||||||
final Bytes extraData = input.readBytes();
|
final long timestamp = headerRlp.readLongScalar();
|
||||||
final Bytes32 mixHashOrPrevRandao = input.readBytes32();
|
final Bytes extraData = headerRlp.readBytes();
|
||||||
final long nonce = input.readLong();
|
final Bytes32 mixHashOrPrevRandao = headerRlp.readBytes32();
|
||||||
final Wei baseFee = !input.isEndOfCurrentList() ? Wei.of(input.readUInt256Scalar()) : null;
|
final long nonce = headerRlp.readLong();
|
||||||
|
final Wei baseFee =
|
||||||
|
!headerRlp.isEndOfCurrentList() ? Wei.of(headerRlp.readUInt256Scalar()) : null;
|
||||||
final Hash withdrawalHashRoot =
|
final Hash withdrawalHashRoot =
|
||||||
!(input.isEndOfCurrentList() || input.isZeroLengthString())
|
!(headerRlp.isEndOfCurrentList() || headerRlp.isZeroLengthString())
|
||||||
? Hash.wrap(input.readBytes32())
|
? Hash.wrap(headerRlp.readBytes32())
|
||||||
: null;
|
: null;
|
||||||
final Long blobGasUsed = !input.isEndOfCurrentList() ? input.readLongScalar() : null;
|
final Long blobGasUsed = !headerRlp.isEndOfCurrentList() ? headerRlp.readLongScalar() : null;
|
||||||
final BlobGas excessBlobGas =
|
final BlobGas excessBlobGas =
|
||||||
!input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null;
|
!headerRlp.isEndOfCurrentList() ? BlobGas.of(headerRlp.readUInt64Scalar()) : null;
|
||||||
final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null;
|
final Bytes32 parentBeaconBlockRoot =
|
||||||
final Hash requestsHash = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null;
|
!headerRlp.isEndOfCurrentList() ? headerRlp.readBytes32() : null;
|
||||||
input.leaveList();
|
final Hash requestsHash =
|
||||||
|
!headerRlp.isEndOfCurrentList() ? Hash.wrap(headerRlp.readBytes32()) : null;
|
||||||
|
headerRlp.leaveList();
|
||||||
return new BlockHeader(
|
return new BlockHeader(
|
||||||
parentHash,
|
parentHash,
|
||||||
ommersHash,
|
ommersHash,
|
||||||
@@ -242,7 +304,8 @@ public class BlockHeader extends SealableBlockHeader
|
|||||||
excessBlobGas,
|
excessBlobGas,
|
||||||
parentBeaconBlockRoot,
|
parentBeaconBlockRoot,
|
||||||
requestsHash,
|
requestsHash,
|
||||||
blockHeaderFunctions);
|
blockHeaderFunctions,
|
||||||
|
Optional.of(headerRlp.raw()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelega
|
|||||||
Bytes.fromHexStringLenient(nonce).toLong(),
|
Bytes.fromHexStringLenient(nonce).toLong(),
|
||||||
SIGNATURE_ALGORITHM
|
SIGNATURE_ALGORITHM
|
||||||
.get()
|
.get()
|
||||||
.createSignature(
|
.createCodeDelegationSignature(
|
||||||
Bytes.fromHexStringLenient(r).toUnsignedBigInteger(),
|
Bytes.fromHexStringLenient(r).toUnsignedBigInteger(),
|
||||||
Bytes.fromHexStringLenient(s).toUnsignedBigInteger(),
|
Bytes.fromHexStringLenient(s).toUnsignedBigInteger(),
|
||||||
Bytes.fromHexStringLenient(v).get(0)));
|
Bytes.fromHexStringLenient(v).get(0)));
|
||||||
@@ -121,6 +121,12 @@ public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelega
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Address> authorizer() {
|
public Optional<Address> authorizer() {
|
||||||
|
// recId needs to be between 0 and 3, otherwise the signature is invalid
|
||||||
|
// which means we can't recover the authorizer.
|
||||||
|
if (signature.getRecId() < 0 || signature.getRecId() > 3) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
return authorizerSupplier.get();
|
return authorizerSupplier.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,4 +278,20 @@ public class CodeDelegation implements org.hyperledger.besu.datatypes.CodeDelega
|
|||||||
return new CodeDelegation(chainId, address, nonce, signature);
|
return new CodeDelegation(chainId, address, nonce, signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CodeDelegation{"
|
||||||
|
+ "chainId="
|
||||||
|
+ chainId
|
||||||
|
+ ", address="
|
||||||
|
+ address
|
||||||
|
+ ", nonce="
|
||||||
|
+ nonce
|
||||||
|
+ ", signature="
|
||||||
|
+ signature
|
||||||
|
+ ", authorizerSupplier="
|
||||||
|
+ authorizerSupplier
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ public class Transaction
|
|||||||
private final Optional<BlobsWithCommitments> blobsWithCommitments;
|
private final Optional<BlobsWithCommitments> blobsWithCommitments;
|
||||||
private final Optional<List<CodeDelegation>> maybeCodeDelegationList;
|
private final Optional<List<CodeDelegation>> maybeCodeDelegationList;
|
||||||
|
|
||||||
|
private final Optional<Bytes> rawRlp;
|
||||||
|
|
||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
@@ -181,7 +183,8 @@ public class Transaction
|
|||||||
final Optional<BigInteger> chainId,
|
final Optional<BigInteger> chainId,
|
||||||
final Optional<List<VersionedHash>> versionedHashes,
|
final Optional<List<VersionedHash>> versionedHashes,
|
||||||
final Optional<BlobsWithCommitments> blobsWithCommitments,
|
final Optional<BlobsWithCommitments> blobsWithCommitments,
|
||||||
final Optional<List<CodeDelegation>> maybeCodeDelegationList) {
|
final Optional<List<CodeDelegation>> maybeCodeDelegationList,
|
||||||
|
final Optional<Bytes> rawRlp) {
|
||||||
|
|
||||||
if (!forCopy) {
|
if (!forCopy) {
|
||||||
if (transactionType.requiresChainId()) {
|
if (transactionType.requiresChainId()) {
|
||||||
@@ -242,6 +245,7 @@ public class Transaction
|
|||||||
this.versionedHashes = versionedHashes;
|
this.versionedHashes = versionedHashes;
|
||||||
this.blobsWithCommitments = blobsWithCommitments;
|
this.blobsWithCommitments = blobsWithCommitments;
|
||||||
this.maybeCodeDelegationList = maybeCodeDelegationList;
|
this.maybeCodeDelegationList = maybeCodeDelegationList;
|
||||||
|
this.rawRlp = rawRlp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -665,6 +669,10 @@ public class Transaction
|
|||||||
return getEffectivePriorityFeePerGas(baseFeePerGas).addExact(baseFeePerGas.orElse(Wei.ZERO));
|
return getEffectivePriorityFeePerGas(baseFeePerGas).addExact(baseFeePerGas.orElse(Wei.ZERO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Bytes> getRawRlp() {
|
||||||
|
return rawRlp;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransactionType getType() {
|
public TransactionType getType() {
|
||||||
return this.transactionType;
|
return this.transactionType;
|
||||||
@@ -1116,7 +1124,8 @@ public class Transaction
|
|||||||
chainId,
|
chainId,
|
||||||
detachedVersionedHashes,
|
detachedVersionedHashes,
|
||||||
detachedBlobsWithCommitments,
|
detachedBlobsWithCommitments,
|
||||||
detachedCodeDelegationList);
|
detachedCodeDelegationList,
|
||||||
|
Optional.empty());
|
||||||
|
|
||||||
// copy also the computed fields, to avoid to recompute them
|
// copy also the computed fields, to avoid to recompute them
|
||||||
copiedTx.sender = this.sender;
|
copiedTx.sender = this.sender;
|
||||||
@@ -1194,6 +1203,7 @@ public class Transaction
|
|||||||
protected List<VersionedHash> versionedHashes = null;
|
protected List<VersionedHash> versionedHashes = null;
|
||||||
private BlobsWithCommitments blobsWithCommitments;
|
private BlobsWithCommitments blobsWithCommitments;
|
||||||
protected Optional<List<CodeDelegation>> codeDelegationAuthorizations = Optional.empty();
|
protected Optional<List<CodeDelegation>> codeDelegationAuthorizations = Optional.empty();
|
||||||
|
protected Bytes rawRlp = null;
|
||||||
|
|
||||||
public Builder copiedFrom(final Transaction toCopy) {
|
public Builder copiedFrom(final Transaction toCopy) {
|
||||||
this.transactionType = toCopy.transactionType;
|
this.transactionType = toCopy.transactionType;
|
||||||
@@ -1299,6 +1309,11 @@ public class Transaction
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder rawRlp(final Bytes rawRlp) {
|
||||||
|
this.rawRlp = rawRlp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder guessType() {
|
public Builder guessType() {
|
||||||
if (codeDelegationAuthorizations.isPresent()) {
|
if (codeDelegationAuthorizations.isPresent()) {
|
||||||
transactionType = TransactionType.DELEGATE_CODE;
|
transactionType = TransactionType.DELEGATE_CODE;
|
||||||
@@ -1338,7 +1353,8 @@ public class Transaction
|
|||||||
chainId,
|
chainId,
|
||||||
Optional.ofNullable(versionedHashes),
|
Optional.ofNullable(versionedHashes),
|
||||||
Optional.ofNullable(blobsWithCommitments),
|
Optional.ofNullable(blobsWithCommitments),
|
||||||
codeDelegationAuthorizations);
|
codeDelegationAuthorizations,
|
||||||
|
Optional.ofNullable(rawRlp));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction signAndBuild(final KeyPair keys) {
|
public Transaction signAndBuild(final KeyPair keys) {
|
||||||
|
|||||||
@@ -37,21 +37,23 @@ class AccessListTransactionDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Transaction decode(final RLPInput rlpInput) {
|
public static Transaction decode(final RLPInput rlpInput) {
|
||||||
rlpInput.enterList();
|
RLPInput transactionRlp = rlpInput.readAsRlp();
|
||||||
|
transactionRlp.enterList();
|
||||||
final Transaction.Builder preSignatureTransactionBuilder =
|
final Transaction.Builder preSignatureTransactionBuilder =
|
||||||
Transaction.builder()
|
Transaction.builder()
|
||||||
.type(TransactionType.ACCESS_LIST)
|
.type(TransactionType.ACCESS_LIST)
|
||||||
.chainId(BigInteger.valueOf(rlpInput.readLongScalar()))
|
.chainId(BigInteger.valueOf(transactionRlp.readLongScalar()))
|
||||||
.nonce(rlpInput.readLongScalar())
|
.nonce(transactionRlp.readLongScalar())
|
||||||
.gasPrice(Wei.of(rlpInput.readUInt256Scalar()))
|
.gasPrice(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.gasLimit(rlpInput.readLongScalar())
|
.gasLimit(transactionRlp.readLongScalar())
|
||||||
.to(
|
.to(
|
||||||
rlpInput.readBytes(
|
transactionRlp.readBytes(
|
||||||
addressBytes -> addressBytes.isEmpty() ? null : Address.wrap(addressBytes)))
|
addressBytes -> addressBytes.isEmpty() ? null : Address.wrap(addressBytes)))
|
||||||
.value(Wei.of(rlpInput.readUInt256Scalar()))
|
.value(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.payload(rlpInput.readBytes())
|
.payload(transactionRlp.readBytes())
|
||||||
|
.rawRlp(transactionRlp.raw())
|
||||||
.accessList(
|
.accessList(
|
||||||
rlpInput.readList(
|
transactionRlp.readList(
|
||||||
accessListEntryRLPInput -> {
|
accessListEntryRLPInput -> {
|
||||||
accessListEntryRLPInput.enterList();
|
accessListEntryRLPInput.enterList();
|
||||||
final AccessListEntry accessListEntry =
|
final AccessListEntry accessListEntry =
|
||||||
@@ -61,18 +63,18 @@ class AccessListTransactionDecoder {
|
|||||||
accessListEntryRLPInput.leaveList();
|
accessListEntryRLPInput.leaveList();
|
||||||
return accessListEntry;
|
return accessListEntry;
|
||||||
}));
|
}));
|
||||||
final byte recId = (byte) rlpInput.readUnsignedByteScalar();
|
final byte recId = (byte) transactionRlp.readUnsignedByteScalar();
|
||||||
final Transaction transaction =
|
final Transaction transaction =
|
||||||
preSignatureTransactionBuilder
|
preSignatureTransactionBuilder
|
||||||
.signature(
|
.signature(
|
||||||
SIGNATURE_ALGORITHM
|
SIGNATURE_ALGORITHM
|
||||||
.get()
|
.get()
|
||||||
.createSignature(
|
.createSignature(
|
||||||
rlpInput.readUInt256Scalar().toUnsignedBigInteger(),
|
transactionRlp.readUInt256Scalar().toUnsignedBigInteger(),
|
||||||
rlpInput.readUInt256Scalar().toUnsignedBigInteger(),
|
transactionRlp.readUInt256Scalar().toUnsignedBigInteger(),
|
||||||
recId))
|
recId))
|
||||||
.build();
|
.build();
|
||||||
rlpInput.leaveList();
|
transactionRlp.leaveList();
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,21 +39,23 @@ public class CodeDelegationTransactionDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Transaction decode(final RLPInput input) {
|
public static Transaction decode(final RLPInput input) {
|
||||||
input.enterList();
|
RLPInput transactionRlp = input.readAsRlp();
|
||||||
final BigInteger chainId = input.readBigIntegerScalar();
|
transactionRlp.enterList();
|
||||||
|
final BigInteger chainId = transactionRlp.readBigIntegerScalar();
|
||||||
final Transaction.Builder builder =
|
final Transaction.Builder builder =
|
||||||
Transaction.builder()
|
Transaction.builder()
|
||||||
.type(TransactionType.DELEGATE_CODE)
|
.type(TransactionType.DELEGATE_CODE)
|
||||||
.chainId(chainId)
|
.chainId(chainId)
|
||||||
.nonce(input.readLongScalar())
|
.nonce(transactionRlp.readLongScalar())
|
||||||
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar()))
|
.maxPriorityFeePerGas(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.maxFeePerGas(Wei.of(input.readUInt256Scalar()))
|
.maxFeePerGas(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.gasLimit(input.readLongScalar())
|
.gasLimit(transactionRlp.readLongScalar())
|
||||||
.to(input.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
|
.to(transactionRlp.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
|
||||||
.value(Wei.of(input.readUInt256Scalar()))
|
.value(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.payload(input.readBytes())
|
.payload(transactionRlp.readBytes())
|
||||||
|
.rawRlp(transactionRlp.raw())
|
||||||
.accessList(
|
.accessList(
|
||||||
input.readList(
|
transactionRlp.readList(
|
||||||
accessListEntryRLPInput -> {
|
accessListEntryRLPInput -> {
|
||||||
accessListEntryRLPInput.enterList();
|
accessListEntryRLPInput.enterList();
|
||||||
final AccessListEntry accessListEntry =
|
final AccessListEntry accessListEntry =
|
||||||
@@ -63,13 +65,14 @@ public class CodeDelegationTransactionDecoder {
|
|||||||
accessListEntryRLPInput.leaveList();
|
accessListEntryRLPInput.leaveList();
|
||||||
return accessListEntry;
|
return accessListEntry;
|
||||||
}))
|
}))
|
||||||
.codeDelegations(input.readList(CodeDelegationTransactionDecoder::decodeInnerPayload));
|
.codeDelegations(
|
||||||
|
transactionRlp.readList(CodeDelegationTransactionDecoder::decodeInnerPayload));
|
||||||
|
|
||||||
final byte recId = (byte) input.readUnsignedByteScalar();
|
final byte recId = (byte) transactionRlp.readUnsignedByteScalar();
|
||||||
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
|
final BigInteger r = transactionRlp.readUInt256Scalar().toUnsignedBigInteger();
|
||||||
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
|
final BigInteger s = transactionRlp.readUInt256Scalar().toUnsignedBigInteger();
|
||||||
|
|
||||||
input.leaveList();
|
transactionRlp.leaveList();
|
||||||
|
|
||||||
return builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build();
|
return builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,21 +37,23 @@ public class EIP1559TransactionDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Transaction decode(final RLPInput input) {
|
public static Transaction decode(final RLPInput input) {
|
||||||
input.enterList();
|
RLPInput transactionRlp = input.readAsRlp();
|
||||||
final BigInteger chainId = input.readBigIntegerScalar();
|
transactionRlp.enterList();
|
||||||
|
final BigInteger chainId = transactionRlp.readBigIntegerScalar();
|
||||||
final Transaction.Builder builder =
|
final Transaction.Builder builder =
|
||||||
Transaction.builder()
|
Transaction.builder()
|
||||||
.type(TransactionType.EIP1559)
|
.type(TransactionType.EIP1559)
|
||||||
.chainId(chainId)
|
.chainId(chainId)
|
||||||
.nonce(input.readLongScalar())
|
.nonce(transactionRlp.readLongScalar())
|
||||||
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar()))
|
.maxPriorityFeePerGas(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.maxFeePerGas(Wei.of(input.readUInt256Scalar()))
|
.maxFeePerGas(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.gasLimit(input.readLongScalar())
|
.gasLimit(transactionRlp.readLongScalar())
|
||||||
.to(input.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
|
.to(transactionRlp.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
|
||||||
.value(Wei.of(input.readUInt256Scalar()))
|
.value(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.payload(input.readBytes())
|
.payload(transactionRlp.readBytes())
|
||||||
|
.rawRlp(transactionRlp.raw())
|
||||||
.accessList(
|
.accessList(
|
||||||
input.readList(
|
transactionRlp.readList(
|
||||||
accessListEntryRLPInput -> {
|
accessListEntryRLPInput -> {
|
||||||
accessListEntryRLPInput.enterList();
|
accessListEntryRLPInput.enterList();
|
||||||
final AccessListEntry accessListEntry =
|
final AccessListEntry accessListEntry =
|
||||||
@@ -61,18 +63,18 @@ public class EIP1559TransactionDecoder {
|
|||||||
accessListEntryRLPInput.leaveList();
|
accessListEntryRLPInput.leaveList();
|
||||||
return accessListEntry;
|
return accessListEntry;
|
||||||
}));
|
}));
|
||||||
final byte recId = (byte) input.readUnsignedByteScalar();
|
final byte recId = (byte) transactionRlp.readUnsignedByteScalar();
|
||||||
final Transaction transaction =
|
final Transaction transaction =
|
||||||
builder
|
builder
|
||||||
.signature(
|
.signature(
|
||||||
SIGNATURE_ALGORITHM
|
SIGNATURE_ALGORITHM
|
||||||
.get()
|
.get()
|
||||||
.createSignature(
|
.createSignature(
|
||||||
input.readUInt256Scalar().toUnsignedBigInteger(),
|
transactionRlp.readUInt256Scalar().toUnsignedBigInteger(),
|
||||||
input.readUInt256Scalar().toUnsignedBigInteger(),
|
transactionRlp.readUInt256Scalar().toUnsignedBigInteger(),
|
||||||
recId))
|
recId))
|
||||||
.build();
|
.build();
|
||||||
input.leaveList();
|
transactionRlp.leaveList();
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,18 +41,20 @@ public class FrontierTransactionDecoder {
|
|||||||
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
|
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
|
||||||
|
|
||||||
public static Transaction decode(final RLPInput input) {
|
public static Transaction decode(final RLPInput input) {
|
||||||
input.enterList();
|
RLPInput transactionRlp = input.readAsRlp();
|
||||||
|
transactionRlp.enterList();
|
||||||
final Transaction.Builder builder =
|
final Transaction.Builder builder =
|
||||||
Transaction.builder()
|
Transaction.builder()
|
||||||
.type(TransactionType.FRONTIER)
|
.type(TransactionType.FRONTIER)
|
||||||
.nonce(input.readLongScalar())
|
.nonce(transactionRlp.readLongScalar())
|
||||||
.gasPrice(Wei.of(input.readUInt256Scalar()))
|
.gasPrice(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.gasLimit(input.readLongScalar())
|
.gasLimit(transactionRlp.readLongScalar())
|
||||||
.to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v)))
|
.to(transactionRlp.readBytes(v -> v.size() == 0 ? null : Address.wrap(v)))
|
||||||
.value(Wei.of(input.readUInt256Scalar()))
|
.value(Wei.of(transactionRlp.readUInt256Scalar()))
|
||||||
.payload(input.readBytes());
|
.payload(transactionRlp.readBytes())
|
||||||
|
.rawRlp(transactionRlp.raw());
|
||||||
|
|
||||||
final BigInteger v = input.readBigIntegerScalar();
|
final BigInteger v = transactionRlp.readBigIntegerScalar();
|
||||||
final byte recId;
|
final byte recId;
|
||||||
Optional<BigInteger> chainId = Optional.empty();
|
Optional<BigInteger> chainId = Optional.empty();
|
||||||
if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) {
|
if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) {
|
||||||
@@ -64,11 +66,11 @@ public class FrontierTransactionDecoder {
|
|||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
String.format("An unsupported encoded `v` value of %s was found", v));
|
String.format("An unsupported encoded `v` value of %s was found", v));
|
||||||
}
|
}
|
||||||
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger();
|
final BigInteger r = transactionRlp.readUInt256Scalar().toUnsignedBigInteger();
|
||||||
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger();
|
final BigInteger s = transactionRlp.readUInt256Scalar().toUnsignedBigInteger();
|
||||||
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId);
|
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId);
|
||||||
|
|
||||||
input.leaveList();
|
transactionRlp.leaveList();
|
||||||
|
|
||||||
chainId.ifPresent(builder::chainId);
|
chainId.ifPresent(builder::chainId);
|
||||||
return builder.signature(signature).build();
|
return builder.signature(signature).build();
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class TransactionEncoder {
|
|||||||
final RLPOutput rlpOutput,
|
final RLPOutput rlpOutput,
|
||||||
final EncodingContext encodingContext) {
|
final EncodingContext encodingContext) {
|
||||||
final TransactionType transactionType = getTransactionType(transaction);
|
final TransactionType transactionType = getTransactionType(transaction);
|
||||||
|
|
||||||
Bytes opaqueBytes = encodeOpaqueBytes(transaction, encodingContext);
|
Bytes opaqueBytes = encodeOpaqueBytes(transaction, encodingContext);
|
||||||
encodeRLP(transactionType, opaqueBytes, rlpOutput);
|
encodeRLP(transactionType, opaqueBytes, rlpOutput);
|
||||||
}
|
}
|
||||||
@@ -94,8 +95,16 @@ public class TransactionEncoder {
|
|||||||
} else {
|
} else {
|
||||||
final Encoder encoder = getEncoder(transactionType, encodingContext);
|
final Encoder encoder = getEncoder(transactionType, encodingContext);
|
||||||
final BytesValueRLPOutput out = new BytesValueRLPOutput();
|
final BytesValueRLPOutput out = new BytesValueRLPOutput();
|
||||||
out.writeByte(transaction.getType().getSerializedType());
|
transaction
|
||||||
encoder.encode(transaction, out);
|
.getRawRlp()
|
||||||
|
.ifPresentOrElse(
|
||||||
|
(rawRlp) ->
|
||||||
|
out.writeRLPBytes(
|
||||||
|
Bytes.concatenate(Bytes.of(transactionType.getSerializedType()), rawRlp)),
|
||||||
|
() -> {
|
||||||
|
out.writeByte(transaction.getType().getSerializedType());
|
||||||
|
encoder.encode(transaction, out);
|
||||||
|
});
|
||||||
return out.encoded();
|
return out.encoded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet;
|
|||||||
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
|
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.Address;
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
|
import org.hyperledger.besu.datatypes.Hash;
|
||||||
import org.hyperledger.besu.datatypes.TransactionType;
|
import org.hyperledger.besu.datatypes.TransactionType;
|
||||||
import org.hyperledger.besu.datatypes.Wei;
|
import org.hyperledger.besu.datatypes.Wei;
|
||||||
import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
|
import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
|
||||||
@@ -191,6 +192,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockUpdater.commit();
|
blockUpdater.commit();
|
||||||
|
blockUpdater.markTransactionBoundary();
|
||||||
|
|
||||||
currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining();
|
currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining();
|
||||||
if (transaction.getVersionedHashes().isPresent()) {
|
if (transaction.getVersionedHashes().isPresent()) {
|
||||||
@@ -250,6 +252,19 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
|
|||||||
maybeRequests = Optional.of(requestProcessor.get().process(context));
|
maybeRequests = Optional.of(requestProcessor.get().process(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maybeRequests.isPresent() && blockHeader.getRequestsHash().isPresent()) {
|
||||||
|
Hash calculatedRequestHash = BodyValidation.requestsHash(maybeRequests.get());
|
||||||
|
Hash headerRequestsHash = blockHeader.getRequestsHash().get();
|
||||||
|
if (!calculatedRequestHash.equals(headerRequestsHash)) {
|
||||||
|
return new BlockProcessingResult(
|
||||||
|
Optional.empty(),
|
||||||
|
"Requests hash mismatch, calculated: "
|
||||||
|
+ calculatedRequestHash.toHexString()
|
||||||
|
+ " header: "
|
||||||
|
+ headerRequestsHash.toHexString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
|
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
|
||||||
// no need to log, rewardCoinbase logs the error.
|
// no need to log, rewardCoinbase logs the error.
|
||||||
if (worldState instanceof BonsaiWorldState) {
|
if (worldState instanceof BonsaiWorldState) {
|
||||||
|
|||||||
@@ -105,11 +105,6 @@ public class CodeDelegationProcessor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeDelegation.signature().getRecId() != 0 && codeDelegation.signature().getRecId() != 1) {
|
|
||||||
LOG.trace("Invalid signature for code delegation. RecId must be 0 or 1.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Optional<Address> authorizer = codeDelegation.authorizer();
|
final Optional<Address> authorizer = codeDelegation.authorizer();
|
||||||
if (authorizer.isEmpty()) {
|
if (authorizer.isEmpty()) {
|
||||||
LOG.trace("Invalid signature for code delegation");
|
LOG.trace("Invalid signature for code delegation");
|
||||||
@@ -126,6 +121,10 @@ public class CodeDelegationProcessor {
|
|||||||
MutableAccount authority;
|
MutableAccount authority;
|
||||||
boolean authorityDoesAlreadyExist = false;
|
boolean authorityDoesAlreadyExist = false;
|
||||||
if (maybeAuthorityAccount.isEmpty()) {
|
if (maybeAuthorityAccount.isEmpty()) {
|
||||||
|
// only create an account if nonce is valid
|
||||||
|
if (codeDelegation.nonce() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
authority = evmWorldUpdater.createAccount(authorizer.get());
|
authority = evmWorldUpdater.createAccount(authorizer.get());
|
||||||
} else {
|
} else {
|
||||||
authority = maybeAuthorityAccount.get();
|
authority = maybeAuthorityAccount.get();
|
||||||
@@ -146,7 +145,7 @@ public class CodeDelegationProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (authorityDoesAlreadyExist) {
|
if (authorityDoesAlreadyExist) {
|
||||||
result.incremenentAlreadyExistingDelegators();
|
result.incrementAlreadyExistingDelegators();
|
||||||
}
|
}
|
||||||
|
|
||||||
evmWorldUpdater
|
evmWorldUpdater
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class CodeDelegationResult {
|
|||||||
accessedDelegatorAddresses.add(address);
|
accessedDelegatorAddresses.add(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incremenentAlreadyExistingDelegators() {
|
public void incrementAlreadyExistingDelegators() {
|
||||||
alreadyExistingDelegators += 1;
|
alreadyExistingDelegators += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ public class ProtocolSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the TransctionReceiptFactory used in this specification
|
* Returns the TransactionReceiptFactory used in this specification
|
||||||
*
|
*
|
||||||
* @return the transaction receipt factory
|
* @return the transaction receipt factory
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
|
|||||||
private static final Logger LOG = LoggerFactory.getLogger(PragueBlockHashProcessor.class);
|
private static final Logger LOG = LoggerFactory.getLogger(PragueBlockHashProcessor.class);
|
||||||
|
|
||||||
public static final Address HISTORY_STORAGE_ADDRESS =
|
public static final Address HISTORY_STORAGE_ADDRESS =
|
||||||
Address.fromHexString("0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC");
|
Address.fromHexString("0x0000f90827f1c53a10cb7a02335b175320002935");
|
||||||
|
|
||||||
/** The HISTORY_SERVE_WINDOW */
|
/** The HISTORY_SERVE_WINDOW */
|
||||||
private static final long HISTORY_SERVE_WINDOW = 8191;
|
private static final long HISTORY_SERVE_WINDOW = 8191;
|
||||||
@@ -68,9 +68,11 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
|
|||||||
super.processBlockHashes(mutableWorldState, currentBlockHeader);
|
super.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||||
|
|
||||||
WorldUpdater worldUpdater = mutableWorldState.updater();
|
WorldUpdater worldUpdater = mutableWorldState.updater();
|
||||||
final MutableAccount historyStorageAccount = worldUpdater.getOrCreate(historyStorageAddress);
|
final MutableAccount historyStorageAccount = worldUpdater.getAccount(historyStorageAddress);
|
||||||
|
|
||||||
if (currentBlockHeader.getNumber() > 0) {
|
if (historyStorageAccount != null
|
||||||
|
&& historyStorageAccount.getNonce() > 0
|
||||||
|
&& currentBlockHeader.getNumber() > 0) {
|
||||||
storeParentHash(historyStorageAccount, currentBlockHeader);
|
storeParentHash(historyStorageAccount, currentBlockHeader);
|
||||||
}
|
}
|
||||||
worldUpdater.commit();
|
worldUpdater.commit();
|
||||||
|
|||||||
@@ -14,12 +14,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.hyperledger.besu.ethereum.mainnet.requests;
|
package org.hyperledger.besu.ethereum.mainnet.requests;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.RequestType;
|
||||||
import org.hyperledger.besu.ethereum.core.Request;
|
import org.hyperledger.besu.ethereum.core.Request;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Comparators;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -46,15 +48,25 @@ public class MainnetRequestsValidator implements RequestsValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isRequestOrderValid(maybeRequests.get())) {
|
List<Request> requests = maybeRequests.get();
|
||||||
LOG.warn("Ordering across requests must be ascending by type");
|
if (!areRequestTypesUniqueAndOrderValid(requests)) {
|
||||||
|
LOG.warn("Request types must be unique and ordering must be ascending by type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (containsRequestWithEmptyData(requests)) {
|
||||||
|
LOG.warn("Request must not be empty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRequestOrderValid(final List<Request> requests) {
|
private static boolean areRequestTypesUniqueAndOrderValid(final List<Request> requests) {
|
||||||
return Ordering.natural().onResultOf(Request::getType).isOrdered(requests);
|
final List<RequestType> requestTypes = requests.stream().map(Request::type).toList();
|
||||||
|
return Comparators.isInStrictOrder(requestTypes, Comparator.naturalOrder());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean containsRequestWithEmptyData(final List<Request> requests) {
|
||||||
|
return requests.stream().anyMatch(request -> request.getData().isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public class RequestContractAddresses {
|
|||||||
private final Address consolidationRequestContractAddress;
|
private final Address consolidationRequestContractAddress;
|
||||||
|
|
||||||
public static final Address DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS =
|
public static final Address DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS =
|
||||||
Address.fromHexString("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA");
|
Address.fromHexString("0x00000961ef480eb55e80d19ad83579a64c007002");
|
||||||
public static final Address DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS =
|
public static final Address DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS =
|
||||||
Address.fromHexString("0x00431F263cE400f4455c2dCf564e53007Ca4bbBb");
|
Address.fromHexString("0x0000bbddc7ce488642fb579f8b00f3a590007251");
|
||||||
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =
|
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =
|
||||||
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
|
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
import org.apache.tuweni.units.bigints.UInt256;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulates the execution of a block, processing transactions and applying state overrides. This
|
* Simulates the execution of a block, processing transactions and applying state overrides. This
|
||||||
@@ -248,19 +247,7 @@ public class BlockSimulator {
|
|||||||
for (Address accountToOverride : stateOverrideMap.keySet()) {
|
for (Address accountToOverride : stateOverrideMap.keySet()) {
|
||||||
final StateOverride override = stateOverrideMap.get(accountToOverride);
|
final StateOverride override = stateOverrideMap.get(accountToOverride);
|
||||||
MutableAccount account = updater.getOrCreate(accountToOverride);
|
MutableAccount account = updater.getOrCreate(accountToOverride);
|
||||||
override.getNonce().ifPresent(account::setNonce);
|
TransactionSimulator.applyOverrides(account, override);
|
||||||
if (override.getBalance().isPresent()) {
|
|
||||||
account.setBalance(override.getBalance().get());
|
|
||||||
}
|
|
||||||
override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n)));
|
|
||||||
override
|
|
||||||
.getStateDiff()
|
|
||||||
.ifPresent(
|
|
||||||
d ->
|
|
||||||
d.forEach(
|
|
||||||
(key, value) ->
|
|
||||||
account.setStorageValue(
|
|
||||||
UInt256.fromHexString(key), UInt256.fromHexString(value))));
|
|
||||||
}
|
}
|
||||||
updater.commit();
|
updater.commit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -460,13 +460,21 @@ public class TransactionSimulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected void applyOverrides(final MutableAccount account, final StateOverride override) {
|
protected static void applyOverrides(final MutableAccount account, final StateOverride override) {
|
||||||
LOG.debug("applying overrides to state for account {}", account.getAddress());
|
LOG.debug("applying overrides to state for account {}", account.getAddress());
|
||||||
override.getNonce().ifPresent(account::setNonce);
|
override.getNonce().ifPresent(account::setNonce);
|
||||||
if (override.getBalance().isPresent()) {
|
override.getBalance().ifPresent(account::setBalance);
|
||||||
account.setBalance(override.getBalance().get());
|
override.getCode().ifPresent(code -> account.setCode(Bytes.fromHexString(code)));
|
||||||
}
|
override
|
||||||
override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n)));
|
.getState()
|
||||||
|
.ifPresent(
|
||||||
|
d -> {
|
||||||
|
account.clearStorage();
|
||||||
|
d.forEach(
|
||||||
|
(key, value) ->
|
||||||
|
account.setStorageValue(
|
||||||
|
UInt256.fromHexString(key), UInt256.fromHexString(value)));
|
||||||
|
});
|
||||||
override
|
override
|
||||||
.getStateDiff()
|
.getStateDiff()
|
||||||
.ifPresent(
|
.ifPresent(
|
||||||
|
|||||||
@@ -499,8 +499,6 @@ public abstract class DiffBasedWorldStateUpdateAccumulator<ACCOUNT extends DiffB
|
|||||||
tracked.setStorageWasCleared(false); // storage already cleared for this transaction
|
tracked.setStorageWasCleared(false); // storage already cleared for this transaction
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getUpdatedAccounts().clear();
|
|
||||||
getDeletedAccounts().clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -598,6 +596,21 @@ public abstract class DiffBasedWorldStateUpdateAccumulator<ACCOUNT extends DiffB
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the boundary of a transaction by clearing tracking collections.
|
||||||
|
*
|
||||||
|
* <p>These tracking collections store changes made during the transaction. After committing the
|
||||||
|
* transaction, they become unnecessary and can be safely cleared.
|
||||||
|
*
|
||||||
|
* <p>Note: If the transaction is not committed before this method is called, any uncommitted
|
||||||
|
* changes will be lost.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void markTransactionBoundary() {
|
||||||
|
getUpdatedAccounts().clear();
|
||||||
|
getDeletedAccounts().clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isModifyingHeadWorldState() {
|
public boolean isModifyingHeadWorldState() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* 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.ethereum.core;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.crypto.KeyPair;
|
||||||
|
import org.hyperledger.besu.crypto.SECPSignature;
|
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithm;
|
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
||||||
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes32;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
class CodeDelegationTest {
|
||||||
|
|
||||||
|
private BigInteger chainId;
|
||||||
|
private Address address;
|
||||||
|
private long nonce;
|
||||||
|
private SECPSignature signature;
|
||||||
|
private SignatureAlgorithm signatureAlgorithm;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
chainId = BigInteger.valueOf(1);
|
||||||
|
address = Address.fromHexString("0x1234567890abcdef1234567890abcdef12345678");
|
||||||
|
nonce = 100;
|
||||||
|
|
||||||
|
signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
|
||||||
|
KeyPair keyPair = signatureAlgorithm.generateKeyPair();
|
||||||
|
signature = signatureAlgorithm.sign(Bytes32.fromHexStringLenient("deadbeef"), keyPair);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldCreateCodeDelegationSuccessfully() {
|
||||||
|
CodeDelegation delegation = new CodeDelegation(chainId, address, nonce, signature);
|
||||||
|
|
||||||
|
assertThat(delegation.chainId()).isEqualTo(chainId);
|
||||||
|
assertThat(delegation.address()).isEqualTo(address);
|
||||||
|
assertThat(delegation.nonce()).isEqualTo(nonce);
|
||||||
|
assertThat(delegation.signature()).isEqualTo(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldBuildCodeDelegationWithBuilder() {
|
||||||
|
CodeDelegation delegation =
|
||||||
|
(CodeDelegation)
|
||||||
|
CodeDelegation.builder()
|
||||||
|
.chainId(chainId)
|
||||||
|
.address(address)
|
||||||
|
.nonce(nonce)
|
||||||
|
.signature(signature)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(delegation).isNotNull();
|
||||||
|
assertThat(delegation.chainId()).isEqualTo(chainId);
|
||||||
|
assertThat(delegation.address()).isEqualTo(address);
|
||||||
|
assertThat(delegation.nonce()).isEqualTo(nonce);
|
||||||
|
assertThat(delegation.signature()).isEqualTo(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowWhenBuildingWithoutAddress() {
|
||||||
|
assertThatThrownBy(
|
||||||
|
() ->
|
||||||
|
CodeDelegation.builder().chainId(chainId).nonce(nonce).signature(signature).build())
|
||||||
|
.isInstanceOf(IllegalStateException.class)
|
||||||
|
.hasMessageContaining("Address must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowWhenBuildingWithoutNonce() {
|
||||||
|
assertThatThrownBy(
|
||||||
|
() ->
|
||||||
|
CodeDelegation.builder()
|
||||||
|
.chainId(chainId)
|
||||||
|
.address(address)
|
||||||
|
.signature(signature)
|
||||||
|
.build())
|
||||||
|
.isInstanceOf(IllegalStateException.class)
|
||||||
|
.hasMessageContaining("Nonce must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowWhenBuildingWithoutSignature() {
|
||||||
|
assertThatThrownBy(
|
||||||
|
() -> CodeDelegation.builder().chainId(chainId).address(address).nonce(nonce).build())
|
||||||
|
.isInstanceOf(IllegalStateException.class)
|
||||||
|
.hasMessageContaining("Signature must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldCreateCodeDelegationUsingFactoryMethod() {
|
||||||
|
CodeDelegation delegation =
|
||||||
|
(CodeDelegation)
|
||||||
|
CodeDelegation.createCodeDelegation(
|
||||||
|
chainId, address, "0x64", "0x1b", "0xabcdef", "0x123456");
|
||||||
|
|
||||||
|
assertThat(delegation).isNotNull();
|
||||||
|
assertThat(delegation.chainId()).isEqualTo(chainId);
|
||||||
|
assertThat(delegation.address()).isEqualTo(address);
|
||||||
|
assertThat(delegation.nonce()).isEqualTo(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnAuthorizerWhenSignatureIsValid() {
|
||||||
|
CodeDelegation delegation = new CodeDelegation(chainId, address, nonce, signature);
|
||||||
|
|
||||||
|
Optional<Address> authorizer = delegation.authorizer();
|
||||||
|
|
||||||
|
assertThat(authorizer).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnEmptyAuthorizerWhenSignatureInvalid() {
|
||||||
|
SECPSignature invalidSignature = Mockito.mock(SECPSignature.class);
|
||||||
|
Mockito.when(invalidSignature.getRecId()).thenReturn((byte) 5); // Invalid recId (>3)
|
||||||
|
|
||||||
|
CodeDelegation delegation = new CodeDelegation(chainId, address, nonce, invalidSignature);
|
||||||
|
|
||||||
|
Optional<Address> authorizer = delegation.authorizer();
|
||||||
|
|
||||||
|
assertThat(authorizer).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnCorrectSignatureValues() {
|
||||||
|
CodeDelegation delegation = new CodeDelegation(chainId, address, nonce, signature);
|
||||||
|
|
||||||
|
assertThat(delegation.v()).isEqualTo(signature.getRecId());
|
||||||
|
assertThat(delegation.r()).isEqualTo(signature.getR());
|
||||||
|
assertThat(delegation.s()).isEqualTo(signature.getS());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSignAndBuildUsingKeyPair() {
|
||||||
|
KeyPair keyPair = signatureAlgorithm.generateKeyPair();
|
||||||
|
|
||||||
|
CodeDelegation delegation =
|
||||||
|
(CodeDelegation)
|
||||||
|
CodeDelegation.builder()
|
||||||
|
.chainId(chainId)
|
||||||
|
.address(address)
|
||||||
|
.nonce(nonce)
|
||||||
|
.signAndBuild(keyPair);
|
||||||
|
|
||||||
|
assertThat(delegation).isNotNull();
|
||||||
|
assertThat(delegation.signature()).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|||||||
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
|
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.TransactionType;
|
||||||
import org.hyperledger.besu.datatypes.Wei;
|
import org.hyperledger.besu.datatypes.Wei;
|
||||||
|
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
|
||||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||||
import org.hyperledger.besu.ethereum.rlp.RLP;
|
import org.hyperledger.besu.ethereum.rlp.RLP;
|
||||||
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
import org.hyperledger.besu.ethereum.rlp.RLPException;
|
||||||
@@ -79,6 +81,20 @@ class TransactionRLPDecoderTest {
|
|||||||
assertThat(transaction.getNonce()).isEqualTo(MAX_NONCE - 1);
|
assertThat(transaction.getNonce()).isEqualTo(MAX_NONCE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testForAccessListTransaction() {
|
||||||
|
BlockDataGenerator gen = new BlockDataGenerator();
|
||||||
|
Transaction accessListTransaction = gen.transaction(TransactionType.ACCESS_LIST);
|
||||||
|
Bytes encodedBytes =
|
||||||
|
TransactionEncoder.encodeOpaqueBytes(accessListTransaction, EncodingContext.BLOCK_BODY);
|
||||||
|
Transaction decodedTransaction =
|
||||||
|
TransactionDecoder.decodeOpaqueBytes(encodedBytes, EncodingContext.BLOCK_BODY);
|
||||||
|
assertThat(accessListTransaction).isEqualTo(decodedTransaction);
|
||||||
|
Bytes reencodedBytes =
|
||||||
|
TransactionEncoder.encodeOpaqueBytes(decodedTransaction, EncodingContext.BLOCK_BODY);
|
||||||
|
assertThat(encodedBytes).isEqualTo(reencodedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
private static Collection<Object[]> dataTransactionSize() {
|
private static Collection<Object[]> dataTransactionSize() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new Object[][] {
|
new Object[][] {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -112,6 +113,23 @@ class CodeDelegationProcessorTest {
|
|||||||
verify(delegationCodeService).processCodeDelegation(authority, DELEGATE_ADDRESS);
|
verify(delegationCodeService).processCodeDelegation(authority, DELEGATE_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotCreateAccountIfNonceIsInvalid() {
|
||||||
|
// Arrange
|
||||||
|
CodeDelegation codeDelegation = createCodeDelegation(CHAIN_ID, 1L);
|
||||||
|
when(transaction.getCodeDelegationList()).thenReturn(Optional.of(List.of(codeDelegation)));
|
||||||
|
when(worldUpdater.getAccount(any())).thenReturn(null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CodeDelegationResult result = processor.process(worldUpdater, transaction);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.alreadyExistingDelegators()).isZero();
|
||||||
|
verify(worldUpdater, never()).createAccount(any());
|
||||||
|
verify(authority, never()).incrementNonce();
|
||||||
|
verify(delegationCodeService, never()).processCodeDelegation(authority, DELEGATE_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldProcessValidDelegationForExistingAccount() {
|
void shouldProcessValidDelegationForExistingAccount() {
|
||||||
// Arrange
|
// Arrange
|
||||||
@@ -150,6 +168,51 @@ class CodeDelegationProcessorTest {
|
|||||||
verify(delegationCodeService, never()).processCodeDelegation(any(), any());
|
verify(delegationCodeService, never()).processCodeDelegation(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSkipOverInvalidMultipleInvalidNonceDelegationsForSameAuthorityForNewAccount() {
|
||||||
|
// Arrange
|
||||||
|
when(worldUpdater.codeDelegationService()).thenReturn(delegationCodeService);
|
||||||
|
var signature1 = new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 0);
|
||||||
|
long cd1_invalidNonce = 2L;
|
||||||
|
var cd1_invalid =
|
||||||
|
new org.hyperledger.besu.ethereum.core.CodeDelegation(
|
||||||
|
CHAIN_ID,
|
||||||
|
Address.fromHexString("0x0000000000000000000000000000000000001000"),
|
||||||
|
cd1_invalidNonce,
|
||||||
|
signature1);
|
||||||
|
var signature2 = new SECPSignature(BigInteger.TWO, BigInteger.TWO, (byte) 0);
|
||||||
|
final long cd2_validNonce = 0L;
|
||||||
|
var cd2_valid =
|
||||||
|
new org.hyperledger.besu.ethereum.core.CodeDelegation(
|
||||||
|
CHAIN_ID,
|
||||||
|
Address.fromHexString("0x0000000000000000000000000000000000001100"),
|
||||||
|
cd2_validNonce,
|
||||||
|
signature2);
|
||||||
|
var signature3 = new SECPSignature(BigInteger.TWO, BigInteger.TWO, (byte) 0);
|
||||||
|
final long cd3_invalidNonce = 0L;
|
||||||
|
var cd3_invalid =
|
||||||
|
new org.hyperledger.besu.ethereum.core.CodeDelegation(
|
||||||
|
CHAIN_ID,
|
||||||
|
Address.fromHexString("0x0000000000000000000000000000000000001200"),
|
||||||
|
cd3_invalidNonce,
|
||||||
|
signature3);
|
||||||
|
when(transaction.getCodeDelegationList())
|
||||||
|
.thenReturn(Optional.of(List.of(cd1_invalid, cd2_valid, cd3_invalid)));
|
||||||
|
|
||||||
|
when(worldUpdater.getAccount(any())).thenReturn(null).thenReturn(null).thenReturn(authority);
|
||||||
|
when(worldUpdater.createAccount(any())).thenReturn(authority);
|
||||||
|
when(authority.getNonce()).thenReturn(0L).thenReturn(1L);
|
||||||
|
when(delegationCodeService.canSetCodeDelegation(any())).thenReturn(true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CodeDelegationResult result = processor.process(worldUpdater, transaction);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.alreadyExistingDelegators()).isZero();
|
||||||
|
verify(authority, times(1)).incrementNonce();
|
||||||
|
verify(delegationCodeService, times(1)).processCodeDelegation(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRejectDelegationWithSGreaterThanHalfCurveOrder() {
|
void shouldRejectDelegationWithSGreaterThanHalfCurveOrder() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|||||||
@@ -45,8 +45,9 @@ class BlockHashProcessorTest {
|
|||||||
mutableWorldState = mock(MutableWorldState.class);
|
mutableWorldState = mock(MutableWorldState.class);
|
||||||
worldUpdater = mock(WorldUpdater.class);
|
worldUpdater = mock(WorldUpdater.class);
|
||||||
account = mock(MutableAccount.class);
|
account = mock(MutableAccount.class);
|
||||||
|
when(account.getNonce()).thenReturn(1L);
|
||||||
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
||||||
when(worldUpdater.getOrCreate(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS))
|
when(worldUpdater.getAccount(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS))
|
||||||
.thenReturn(account);
|
.thenReturn(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ class BlockHashProcessorTest {
|
|||||||
mockAncestorHeaders(currentBlockHeader, 0);
|
mockAncestorHeaders(currentBlockHeader, 0);
|
||||||
|
|
||||||
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||||
verifyNoInteractions(account);
|
verify(account, times(0)).setStorageValue(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -89,6 +90,20 @@ class BlockHashProcessorTest {
|
|||||||
verifyAccount(0, historicalWindow);
|
verifyAccount(0, historicalWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotStoreBlockHashIfContractIsNotDeployed() {
|
||||||
|
when(worldUpdater.getAccount(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS))
|
||||||
|
.thenReturn(null);
|
||||||
|
|
||||||
|
long currentBlock = 1;
|
||||||
|
processor = new PragueBlockHashProcessor();
|
||||||
|
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
|
||||||
|
mockAncestorHeaders(currentBlockHeader, 0);
|
||||||
|
|
||||||
|
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||||
|
verifyNoInteractions(account);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldWriteGenesisHashAtSlot0() {
|
void shouldWriteGenesisHashAtSlot0() {
|
||||||
processor = new PragueBlockHashProcessor();
|
processor = new PragueBlockHashProcessor();
|
||||||
|
|||||||
@@ -55,4 +55,21 @@ class MainnetRequestsValidatorTest {
|
|||||||
new Request(RequestType.CONSOLIDATION, Bytes.of(3)));
|
new Request(RequestType.CONSOLIDATION, Bytes.of(3)));
|
||||||
assertTrue(validator.validate(Optional.of(requests)));
|
assertTrue(validator.validate(Optional.of(requests)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validateFalseForEmptyRequest() {
|
||||||
|
MainnetRequestsValidator validator = new MainnetRequestsValidator();
|
||||||
|
List<Request> requests = List.of(new Request(RequestType.DEPOSIT, Bytes.EMPTY));
|
||||||
|
assertFalse(validator.validate(Optional.of(requests)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validateFalseForDuplicatedRequests() {
|
||||||
|
MainnetRequestsValidator validator = new MainnetRequestsValidator();
|
||||||
|
List<Request> requests =
|
||||||
|
List.of(
|
||||||
|
new Request(RequestType.DEPOSIT, Bytes.of(1)),
|
||||||
|
new Request(RequestType.DEPOSIT, Bytes.of(1)));
|
||||||
|
assertFalse(validator.validate(Optional.of(requests)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.hyperledger.besu.datatypes.Hash;
|
|||||||
import org.hyperledger.besu.datatypes.StateOverride;
|
import org.hyperledger.besu.datatypes.StateOverride;
|
||||||
import org.hyperledger.besu.datatypes.StateOverrideMap;
|
import org.hyperledger.besu.datatypes.StateOverrideMap;
|
||||||
import org.hyperledger.besu.datatypes.Wei;
|
import org.hyperledger.besu.datatypes.Wei;
|
||||||
|
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
||||||
import org.hyperledger.besu.ethereum.GasLimitCalculator;
|
import org.hyperledger.besu.ethereum.GasLimitCalculator;
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||||
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
|
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
|
||||||
@@ -50,11 +51,9 @@ import org.hyperledger.besu.plugin.data.BlockOverrides;
|
|||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
import org.apache.tuweni.units.bigints.UInt256;
|
import org.apache.tuweni.units.bigints.UInt256;
|
||||||
@@ -168,24 +167,25 @@ public class BlockSimulatorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldApplyStateOverridesCorrectly() {
|
public void shouldApplyStateOverridesCorrectly() {
|
||||||
StateOverrideMap stateOverrideMap = mock(StateOverrideMap.class);
|
StateOverrideMap stateOverrideMap = new StateOverrideMap();
|
||||||
Address address = mock(Address.class);
|
Address address = mock(Address.class);
|
||||||
StateOverride stateOverride = mock(StateOverride.class);
|
StateOverride stateOverride =
|
||||||
MutableAccount mutableAccount = mock(MutableAccount.class);
|
new StateOverride.Builder()
|
||||||
|
.withBalance(Wei.of(456L))
|
||||||
|
.withNonce(new UnsignedLongParameter(123L))
|
||||||
|
.withCode("")
|
||||||
|
.withStateDiff(Map.of("0x0", "0x1"))
|
||||||
|
.build();
|
||||||
|
|
||||||
when(stateOverrideMap.keySet()).thenReturn(Set.of(address));
|
stateOverrideMap.put(address, stateOverride);
|
||||||
when(stateOverrideMap.get(address)).thenReturn(stateOverride);
|
|
||||||
|
|
||||||
WorldUpdater worldUpdater = mock(WorldUpdater.class);
|
WorldUpdater worldUpdater = mock(WorldUpdater.class);
|
||||||
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
||||||
|
|
||||||
|
MutableAccount mutableAccount = mock(MutableAccount.class);
|
||||||
|
when(mutableAccount.getAddress()).thenReturn(address);
|
||||||
when(worldUpdater.getOrCreate(address)).thenReturn(mutableAccount);
|
when(worldUpdater.getOrCreate(address)).thenReturn(mutableAccount);
|
||||||
|
|
||||||
when(stateOverride.getNonce()).thenReturn(Optional.of(123L));
|
|
||||||
when(stateOverride.getBalance()).thenReturn(Optional.of(Wei.of(456L)));
|
|
||||||
when(stateOverride.getCode()).thenReturn(Optional.of(""));
|
|
||||||
when(stateOverride.getStateDiff()).thenReturn(Optional.of(new HashMap<>(Map.of("0x0", "0x1"))));
|
|
||||||
|
|
||||||
blockSimulator.applyStateOverrides(stateOverrideMap, mutableWorldState);
|
blockSimulator.applyStateOverrides(stateOverrideMap, mutableWorldState);
|
||||||
|
|
||||||
verify(mutableAccount).setNonce(anyLong());
|
verify(mutableAccount).setNonce(anyLong());
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public class TransactionSimulatorTest {
|
|||||||
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM); // called from logging
|
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM); // called from logging
|
||||||
StateOverride.Builder builder = new StateOverride.Builder();
|
StateOverride.Builder builder = new StateOverride.Builder();
|
||||||
StateOverride override = builder.build();
|
StateOverride override = builder.build();
|
||||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||||
verify(mutableAccount).getAddress();
|
verify(mutableAccount).getAddress();
|
||||||
verifyNoMoreInteractions(mutableAccount);
|
verifyNoMoreInteractions(mutableAccount);
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ public class TransactionSimulatorTest {
|
|||||||
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
|
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
|
||||||
StateOverride.Builder builder = new StateOverride.Builder().withBalance(Wei.of(99));
|
StateOverride.Builder builder = new StateOverride.Builder().withBalance(Wei.of(99));
|
||||||
StateOverride override = builder.build();
|
StateOverride override = builder.build();
|
||||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||||
verify(mutableAccount).setBalance(eq(Wei.of(99)));
|
verify(mutableAccount).setBalance(eq(Wei.of(99)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,25 @@ public class TransactionSimulatorTest {
|
|||||||
StateOverride.Builder builder =
|
StateOverride.Builder builder =
|
||||||
new StateOverride.Builder().withStateDiff(Map.of(storageKey, storageValue));
|
new StateOverride.Builder().withStateDiff(Map.of(storageKey, storageValue));
|
||||||
StateOverride override = builder.build();
|
StateOverride override = builder.build();
|
||||||
transactionSimulator.applyOverrides(mutableAccount, override);
|
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||||
|
verify(mutableAccount)
|
||||||
|
.setStorageValue(
|
||||||
|
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_whenStateOverrides_stateIsUpdated() {
|
||||||
|
MutableAccount mutableAccount = mock(MutableAccount.class);
|
||||||
|
when(mutableAccount.getAddress()).thenReturn(DEFAULT_FROM);
|
||||||
|
final String storageKey = "0x01a2";
|
||||||
|
final String storageValue = "0x00ff";
|
||||||
|
StateOverride.Builder builder =
|
||||||
|
new StateOverride.Builder().withState(Map.of(storageKey, storageValue));
|
||||||
|
StateOverride override = builder.build();
|
||||||
|
TransactionSimulator.applyOverrides(mutableAccount, override);
|
||||||
|
|
||||||
|
verify(mutableAccount).clearStorage();
|
||||||
|
|
||||||
verify(mutableAccount)
|
verify(mutableAccount)
|
||||||
.setStorageValue(
|
.setStorageValue(
|
||||||
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
|
eq(UInt256.fromHexString(storageKey)), eq(UInt256.fromHexString(storageValue)));
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.util;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.Address;
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
@@ -25,6 +26,7 @@ import org.hyperledger.besu.datatypes.Wei;
|
|||||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
||||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
@@ -63,6 +65,7 @@ public class StateOverrideParameterTest {
|
|||||||
|
|
||||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
||||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||||
|
assertFalse(stateOverride.getState().isPresent());
|
||||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +94,7 @@ public class StateOverrideParameterTest {
|
|||||||
assertFalse(stateOverride.getNonce().isPresent());
|
assertFalse(stateOverride.getNonce().isPresent());
|
||||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||||
assertThat(stateOverride.getCode()).isEqualTo(Optional.of(CODE_STRING));
|
assertThat(stateOverride.getCode()).isEqualTo(Optional.of(CODE_STRING));
|
||||||
|
assertFalse(stateOverride.getState().isPresent());
|
||||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +122,7 @@ public class StateOverrideParameterTest {
|
|||||||
|
|
||||||
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
assertThat(stateOverride.getBalance()).isEqualTo(Optional.of(Wei.of(1)));
|
||||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158); // 0x9e
|
assertThat(stateOverride.getNonce().get()).isEqualTo(158); // 0x9e
|
||||||
|
assertFalse(stateOverride.getState().isPresent());
|
||||||
assertFalse(stateOverride.getStateDiff().isPresent());
|
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +138,7 @@ public class StateOverrideParameterTest {
|
|||||||
+ "{"
|
+ "{"
|
||||||
+ "\"balance\": \"0x01\","
|
+ "\"balance\": \"0x01\","
|
||||||
+ "\"nonce\": \"0x9E\","
|
+ "\"nonce\": \"0x9E\","
|
||||||
+ "\"stateDiff\": {"
|
+ "\"state\": {"
|
||||||
+ "\""
|
+ "\""
|
||||||
+ STORAGE_KEY
|
+ STORAGE_KEY
|
||||||
+ "\": \""
|
+ "\": \""
|
||||||
@@ -150,8 +155,9 @@ public class StateOverrideParameterTest {
|
|||||||
final StateOverride stateOverride = stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
final StateOverride stateOverride = stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
||||||
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
assertThat(stateOverride.getNonce().get()).isEqualTo(158);
|
||||||
|
|
||||||
assertTrue(stateOverride.getStateDiff().isPresent());
|
assertTrue(stateOverride.getState().isPresent());
|
||||||
assertThat(stateOverride.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
assertThat(stateOverride.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||||
|
assertFalse(stateOverride.getStateDiff().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -166,7 +172,7 @@ public class StateOverrideParameterTest {
|
|||||||
+ "{"
|
+ "{"
|
||||||
+ "\"balance\": \"0x01\","
|
+ "\"balance\": \"0x01\","
|
||||||
+ "\"nonce\": \"0x9E\","
|
+ "\"nonce\": \"0x9E\","
|
||||||
+ "\"stateDiff\": {"
|
+ "\"state\": {"
|
||||||
+ "\""
|
+ "\""
|
||||||
+ STORAGE_KEY
|
+ STORAGE_KEY
|
||||||
+ "\": \""
|
+ "\": \""
|
||||||
@@ -179,7 +185,7 @@ public class StateOverrideParameterTest {
|
|||||||
+ "{"
|
+ "{"
|
||||||
+ "\"balance\": \"0xFF\","
|
+ "\"balance\": \"0xFF\","
|
||||||
+ "\"nonce\": \"0x9D\","
|
+ "\"nonce\": \"0x9D\","
|
||||||
+ "\"stateDiff\": {"
|
+ "\"state\": {"
|
||||||
+ "\""
|
+ "\""
|
||||||
+ STORAGE_KEY
|
+ STORAGE_KEY
|
||||||
+ "\": \""
|
+ "\": \""
|
||||||
@@ -197,18 +203,35 @@ public class StateOverrideParameterTest {
|
|||||||
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX1));
|
||||||
assertThat(stateOverride1.getNonce().get()).isEqualTo(158);
|
assertThat(stateOverride1.getNonce().get()).isEqualTo(158);
|
||||||
assertThat(stateOverride1.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0x01")));
|
assertThat(stateOverride1.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0x01")));
|
||||||
assertTrue(stateOverride1.getStateDiff().isPresent());
|
assertTrue(stateOverride1.getState().isPresent());
|
||||||
assertThat(stateOverride1.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
assertThat(stateOverride1.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||||
|
assertFalse(stateOverride1.getStateDiff().isPresent());
|
||||||
|
|
||||||
final StateOverride stateOverride2 =
|
final StateOverride stateOverride2 =
|
||||||
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX2));
|
stateOverrideParam.get(Address.fromHexString(ADDRESS_HEX2));
|
||||||
assertThat(stateOverride2.getNonce().get()).isEqualTo(157);
|
assertThat(stateOverride2.getNonce().get()).isEqualTo(157);
|
||||||
assertThat(stateOverride2.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0xFF")));
|
assertThat(stateOverride2.getBalance()).isEqualTo(Optional.of(Wei.fromHexString("0xFF")));
|
||||||
assertTrue(stateOverride2.getStateDiff().isPresent());
|
assertTrue(stateOverride2.getState().isPresent());
|
||||||
assertThat(stateOverride2.getStateDiff().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
assertThat(stateOverride2.getState().get().get(STORAGE_KEY)).isEqualTo(STORAGE_VALUE);
|
||||||
|
assertFalse(stateOverride2.getStateDiff().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonRpcRequest readJsonAsJsonRpcRequest(final String json) throws java.io.IOException {
|
private JsonRpcRequest readJsonAsJsonRpcRequest(final String json) throws java.io.IOException {
|
||||||
return new ObjectMapper().readValue(json, JsonRpcRequest.class);
|
return new ObjectMapper().readValue(json, JsonRpcRequest.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldThrowExceptionWhenStateAndStateDiffAreBothPresent() {
|
||||||
|
Exception exception =
|
||||||
|
assertThrows(
|
||||||
|
IllegalStateException.class,
|
||||||
|
() ->
|
||||||
|
new StateOverride.Builder()
|
||||||
|
.withState(Map.of("0x1234", "0x5678"))
|
||||||
|
.withStateDiff(Map.of("0x1234", "0x5678"))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
final String expectedMessage = "Cannot set both state and stateDiff";
|
||||||
|
assertThat(exception.getMessage()).isEqualTo(expectedMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
"0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": {
|
"0x0000f90827f1c53a10cb7a02335b175320002935": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
|
|||||||
@@ -421,8 +421,8 @@ public abstract class PendingTransaction
|
|||||||
* class changes its structure.
|
* class changes its structure.
|
||||||
*/
|
*/
|
||||||
public interface MemorySize {
|
public interface MemorySize {
|
||||||
int FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE = 904;
|
int FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE = 912;
|
||||||
int EIP1559_AND_EIP4844_SHALLOW_SIZE = 1016;
|
int EIP1559_AND_EIP4844_SHALLOW_SIZE = 1024;
|
||||||
int OPTIONAL_TO_SIZE = 112;
|
int OPTIONAL_TO_SIZE = 112;
|
||||||
int OPTIONAL_CHAIN_ID_SIZE = 80;
|
int OPTIONAL_CHAIN_ID_SIZE = 80;
|
||||||
int PAYLOAD_SHALLOW_SIZE = 32;
|
int PAYLOAD_SHALLOW_SIZE = 32;
|
||||||
|
|||||||
@@ -42,12 +42,10 @@ import org.hyperledger.besu.evm.account.AccountState;
|
|||||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collector;
|
import java.util.stream.Collector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -315,8 +313,6 @@ public class LayeredPendingTransactions implements PendingTransactions {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectTransactions(final PendingTransactions.TransactionSelector selector) {
|
public void selectTransactions(final PendingTransactions.TransactionSelector selector) {
|
||||||
final Set<Address> skipSenders = new HashSet<>();
|
|
||||||
|
|
||||||
final Map<Byte, List<SenderPendingTransactions>> candidateTxsByScore;
|
final Map<Byte, List<SenderPendingTransactions>> candidateTxsByScore;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
// since selecting transactions for block creation is a potential long operation
|
// since selecting transactions for block creation is a potential long operation
|
||||||
@@ -332,50 +328,39 @@ public class LayeredPendingTransactions implements PendingTransactions {
|
|||||||
for (final var senderTxs : entry.getValue()) {
|
for (final var senderTxs : entry.getValue()) {
|
||||||
LOG.trace("Evaluating sender txs {}", senderTxs);
|
LOG.trace("Evaluating sender txs {}", senderTxs);
|
||||||
|
|
||||||
if (!skipSenders.contains(senderTxs.sender())) {
|
for (final var candidatePendingTx : senderTxs.pendingTransactions()) {
|
||||||
|
final var selectionResult = selector.evaluateTransaction(candidatePendingTx);
|
||||||
|
|
||||||
for (final var candidatePendingTx : senderTxs.pendingTransactions()) {
|
LOG.atTrace()
|
||||||
final var selectionResult = selector.evaluateTransaction(candidatePendingTx);
|
.setMessage("Selection result {} for transaction {}")
|
||||||
|
.addArgument(selectionResult)
|
||||||
|
.addArgument(candidatePendingTx::toTraceLog)
|
||||||
|
.log();
|
||||||
|
|
||||||
|
if (selectionResult.discard()) {
|
||||||
|
ethScheduler.scheduleTxWorkerTask(
|
||||||
|
() -> {
|
||||||
|
synchronized (this) {
|
||||||
|
prioritizedTransactions.remove(candidatePendingTx, INVALIDATED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logDiscardedTransaction(candidatePendingTx, selectionResult);
|
||||||
|
} else if (selectionResult.penalize()) {
|
||||||
|
ethScheduler.scheduleTxWorkerTask(
|
||||||
|
() -> {
|
||||||
|
synchronized (this) {
|
||||||
|
prioritizedTransactions.penalize(candidatePendingTx);
|
||||||
|
}
|
||||||
|
});
|
||||||
LOG.atTrace()
|
LOG.atTrace()
|
||||||
.setMessage("Selection result {} for transaction {}")
|
.setMessage("Transaction {} penalized")
|
||||||
.addArgument(selectionResult)
|
|
||||||
.addArgument(candidatePendingTx::toTraceLog)
|
.addArgument(candidatePendingTx::toTraceLog)
|
||||||
.log();
|
.log();
|
||||||
|
}
|
||||||
|
|
||||||
if (selectionResult.discard()) {
|
if (selectionResult.stop()) {
|
||||||
ethScheduler.scheduleTxWorkerTask(
|
LOG.trace("Stopping selection");
|
||||||
() -> {
|
break selection;
|
||||||
synchronized (this) {
|
|
||||||
prioritizedTransactions.remove(candidatePendingTx, INVALIDATED);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
logDiscardedTransaction(candidatePendingTx, selectionResult);
|
|
||||||
} else if (selectionResult.penalize()) {
|
|
||||||
ethScheduler.scheduleTxWorkerTask(
|
|
||||||
() -> {
|
|
||||||
synchronized (this) {
|
|
||||||
prioritizedTransactions.penalize(candidatePendingTx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
LOG.atTrace()
|
|
||||||
.setMessage("Transaction {} penalized")
|
|
||||||
.addArgument(candidatePendingTx::toTraceLog)
|
|
||||||
.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectionResult.stop()) {
|
|
||||||
LOG.trace("Stopping selection");
|
|
||||||
break selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectionResult.selected()) {
|
|
||||||
// avoid processing other txs from this sender if this one is skipped
|
|
||||||
// since the following will not be selected due to the nonce gap
|
|
||||||
LOG.trace("Skipping remaining txs for sender {}", candidatePendingTx.getSender());
|
|
||||||
skipSenders.add(candidatePendingTx.getSender());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package org.hyperledger.besu.ethereum.eth.transactions.layered;
|
package org.hyperledger.besu.ethereum.eth.transactions.layered;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
import static org.hyperledger.besu.datatypes.TransactionType.BLOB;
|
import static org.hyperledger.besu.datatypes.TransactionType.BLOB;
|
||||||
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ADDED;
|
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ADDED;
|
||||||
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ALREADY_KNOWN;
|
import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedResult.ALREADY_KNOWN;
|
||||||
@@ -23,15 +24,13 @@ import static org.hyperledger.besu.ethereum.eth.transactions.TransactionAddedRes
|
|||||||
import static org.hyperledger.besu.ethereum.eth.transactions.layered.AddReason.MOVE;
|
import static org.hyperledger.besu.ethereum.eth.transactions.layered.AddReason.MOVE;
|
||||||
import static org.hyperledger.besu.ethereum.eth.transactions.layered.AddReason.NEW;
|
import static org.hyperledger.besu.ethereum.eth.transactions.layered.AddReason.NEW;
|
||||||
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.DROPPED;
|
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.DROPPED;
|
||||||
|
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.INVALIDATED;
|
||||||
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.REPLACED;
|
import static org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredRemovalReason.PoolRemovalReason.REPLACED;
|
||||||
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE;
|
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE;
|
||||||
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE;
|
import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE;
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOB_PRICE_BELOW_CURRENT_MIN;
|
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_FULL;
|
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_FULL;
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD;
|
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD;
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.CURRENT_TX_PRICE_BELOW_MIN;
|
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
|
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
|
||||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_GAS;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
@@ -49,6 +48,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolCo
|
|||||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionAddedListener;
|
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionAddedListener;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionDroppedListener;
|
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactionDroppedListener;
|
||||||
|
import org.hyperledger.besu.ethereum.eth.transactions.RemovalReason;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolMetrics;
|
||||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolReplacementHandler;
|
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolReplacementHandler;
|
||||||
@@ -57,10 +57,12 @@ import org.hyperledger.besu.evm.account.Account;
|
|||||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
|
import java.util.SequencedMap;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -479,46 +481,6 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
|
|||||||
assertThat(iterationOrder).containsExactly(transaction0, transaction1, transaction2);
|
assertThat(iterationOrder).containsExactly(transaction0, transaction1, transaction2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource
|
|
||||||
public void ignoreSenderTransactionsAfterASkippedOne(
|
|
||||||
final TransactionSelectionResult skipSelectionResult) {
|
|
||||||
final Transaction transaction0a = createTransaction(0, DEFAULT_BASE_FEE.add(Wei.of(20)), KEYS1);
|
|
||||||
final Transaction transaction1a = createTransaction(1, DEFAULT_BASE_FEE.add(Wei.of(20)), KEYS1);
|
|
||||||
final Transaction transaction2a = createTransaction(2, DEFAULT_BASE_FEE.add(Wei.of(20)), KEYS1);
|
|
||||||
final Transaction transaction0b = createTransaction(0, DEFAULT_BASE_FEE.add(Wei.of(10)), KEYS2);
|
|
||||||
|
|
||||||
pendingTransactions.addTransaction(
|
|
||||||
createLocalPendingTransaction(transaction0a), Optional.empty());
|
|
||||||
pendingTransactions.addTransaction(
|
|
||||||
createLocalPendingTransaction(transaction1a), Optional.empty());
|
|
||||||
pendingTransactions.addTransaction(
|
|
||||||
createLocalPendingTransaction(transaction2a), Optional.empty());
|
|
||||||
pendingTransactions.addTransaction(
|
|
||||||
createLocalPendingTransaction(transaction0b), Optional.empty());
|
|
||||||
|
|
||||||
final List<Transaction> iterationOrder = new ArrayList<>(3);
|
|
||||||
pendingTransactions.selectTransactions(
|
|
||||||
pendingTx -> {
|
|
||||||
iterationOrder.add(pendingTx.getTransaction());
|
|
||||||
// pretending that the 2nd tx of the 1st sender is not selected
|
|
||||||
return pendingTx.getNonce() == 1 ? skipSelectionResult : SELECTED;
|
|
||||||
});
|
|
||||||
|
|
||||||
// the 3rd tx of the 1st must not be processed, since the 2nd is skipped
|
|
||||||
// but the 2nd sender must not be affected
|
|
||||||
assertThat(iterationOrder).containsExactly(transaction0a, transaction1a, transaction0b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Stream<TransactionSelectionResult> ignoreSenderTransactionsAfterASkippedOne() {
|
|
||||||
return Stream.of(
|
|
||||||
CURRENT_TX_PRICE_BELOW_MIN,
|
|
||||||
BLOB_PRICE_BELOW_CURRENT_MIN,
|
|
||||||
TX_TOO_LARGE_FOR_REMAINING_GAS,
|
|
||||||
TransactionSelectionResult.invalidTransient(GAS_PRICE_BELOW_CURRENT_BASE_FEE.name()),
|
|
||||||
TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void notForceNonceOrderWhenSendersDiffer() {
|
public void notForceNonceOrderWhenSendersDiffer() {
|
||||||
final Account sender2 = mock(Account.class);
|
final Account sender2 = mock(Account.class);
|
||||||
@@ -547,9 +509,10 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
|
|||||||
@Test
|
@Test
|
||||||
public void invalidTransactionIsDeletedFromPendingTransactions() {
|
public void invalidTransactionIsDeletedFromPendingTransactions() {
|
||||||
final var pendingTx0 = createRemotePendingTransaction(transaction0);
|
final var pendingTx0 = createRemotePendingTransaction(transaction0);
|
||||||
final var pendingTx1 = createRemotePendingTransaction(transaction1);
|
|
||||||
pendingTransactions.addTransaction(pendingTx0, Optional.empty());
|
pendingTransactions.addTransaction(pendingTx0, Optional.empty());
|
||||||
pendingTransactions.addTransaction(pendingTx1, Optional.empty());
|
|
||||||
|
final var droppedTxCollector = new DroppedTransactionCollector();
|
||||||
|
pendingTransactions.subscribeDroppedTransactions(droppedTxCollector);
|
||||||
|
|
||||||
final List<PendingTransaction> parsedTransactions = new ArrayList<>(1);
|
final List<PendingTransaction> parsedTransactions = new ArrayList<>(1);
|
||||||
pendingTransactions.selectTransactions(
|
pendingTransactions.selectTransactions(
|
||||||
@@ -558,11 +521,11 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
|
|||||||
return TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name());
|
return TransactionSelectionResult.invalid(UPFRONT_COST_EXCEEDS_BALANCE.name());
|
||||||
});
|
});
|
||||||
|
|
||||||
// only the first is processed since not being selected will automatically skip the processing
|
// assert that first tx is removed from the pool
|
||||||
// all the other txs from the same sender
|
assertThat(droppedTxCollector.droppedTransactions)
|
||||||
|
.containsExactly(entry(transaction0, INVALIDATED));
|
||||||
assertThat(parsedTransactions).containsExactly(pendingTx0);
|
assertThat(parsedTransactions).containsExactly(pendingTx0);
|
||||||
assertThat(pendingTransactions.getPendingTransactions()).containsExactly(pendingTx1);
|
assertThat(pendingTransactions.getPendingTransactions()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -947,4 +910,13 @@ public class LayeredPendingTransactionsTest extends BaseTransactionPoolTest {
|
|||||||
ReadyTransactions readyTransactions,
|
ReadyTransactions readyTransactions,
|
||||||
SparseTransactions sparseTransactions,
|
SparseTransactions sparseTransactions,
|
||||||
EvictCollectorLayer evictedCollector) {}
|
EvictCollectorLayer evictedCollector) {}
|
||||||
|
|
||||||
|
static class DroppedTransactionCollector implements PendingTransactionDroppedListener {
|
||||||
|
final SequencedMap<Transaction, RemovalReason> droppedTransactions = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTransactionDropped(final Transaction transaction, final RemovalReason reason) {
|
||||||
|
droppedTransactions.put(transaction, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm;
|
|||||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
||||||
import org.hyperledger.besu.datatypes.AccessListEntry;
|
import org.hyperledger.besu.datatypes.AccessListEntry;
|
||||||
import org.hyperledger.besu.datatypes.Address;
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
|
import org.hyperledger.besu.datatypes.BlobGas;
|
||||||
import org.hyperledger.besu.datatypes.CodeDelegation;
|
import org.hyperledger.besu.datatypes.CodeDelegation;
|
||||||
import org.hyperledger.besu.datatypes.Hash;
|
import org.hyperledger.besu.datatypes.Hash;
|
||||||
import org.hyperledger.besu.datatypes.TransactionType;
|
import org.hyperledger.besu.datatypes.TransactionType;
|
||||||
@@ -348,10 +349,12 @@ public class T8nExecutor {
|
|||||||
Blockchain blockchain = new T8nBlockchain(referenceTestEnv, protocolSpec);
|
Blockchain blockchain = new T8nBlockchain(referenceTestEnv, protocolSpec);
|
||||||
final BlockHeader blockHeader = referenceTestEnv.parentBlockHeader(protocolSpec);
|
final BlockHeader blockHeader = referenceTestEnv.parentBlockHeader(protocolSpec);
|
||||||
final MainnetTransactionProcessor processor = protocolSpec.getTransactionProcessor();
|
final MainnetTransactionProcessor processor = protocolSpec.getTransactionProcessor();
|
||||||
final Wei blobGasPrice =
|
final BlobGas excessBlobGas =
|
||||||
protocolSpec
|
Optional.ofNullable(referenceTestEnv.getParentExcessBlobGas())
|
||||||
.getFeeMarket()
|
.map(
|
||||||
.blobGasPricePerGas(calculateExcessBlobGasForParent(protocolSpec, blockHeader));
|
__ -> calculateExcessBlobGasForParent(protocolSpec, blockHeader)) // blockchain-test
|
||||||
|
.orElse(blockHeader.getExcessBlobGas().orElse(BlobGas.ZERO)); // state-test
|
||||||
|
final Wei blobGasPrice = protocolSpec.getFeeMarket().blobGasPricePerGas(excessBlobGas);
|
||||||
long blobGasLimit = protocolSpec.getGasLimitCalculator().currentBlobGasLimit();
|
long blobGasLimit = protocolSpec.getGasLimitCalculator().currentBlobGasLimit();
|
||||||
|
|
||||||
if (!referenceTestEnv.isStateTest()) {
|
if (!referenceTestEnv.isStateTest()) {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
"blobGasUsed": "0x00",
|
"blobGasUsed": "0x00",
|
||||||
"excessBlobGas": "0x00",
|
"excessBlobGas": "0x00",
|
||||||
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
"hash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678"
|
"hash": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369"
|
||||||
},
|
},
|
||||||
"pre": {
|
"pre": {
|
||||||
"0x00000000219ab540356cbb839cbe05303d7705fa": {
|
"0x00000000219ab540356cbb839cbe05303d7705fa": {
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
"balance": "0x00",
|
"balance": "0x00",
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
"storage": {
|
"storage": {
|
||||||
"0x00": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678"
|
"0x00": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
|
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
|
||||||
@@ -194,15 +194,15 @@
|
|||||||
"storage": {}
|
"storage": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lastblockhash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f",
|
"lastblockhash": "0x606a39bef40699cba8e82cac36274317a4a9f965db16e67121897e8144dd2ec6",
|
||||||
"genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0",
|
"genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855c0c0c0c0",
|
||||||
"blocks": [
|
"blocks": [
|
||||||
{
|
{
|
||||||
"blockHeader": {
|
"blockHeader": {
|
||||||
"parentHash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678",
|
"parentHash": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369",
|
||||||
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
"coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
"coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||||
"stateRoot": "0x61171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246",
|
"stateRoot": "0x0dc49ca54f4370756d0f863551487c2bbc3a327891f9993b10d3985935bc1198",
|
||||||
"transactionsTrie": "0xec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3",
|
"transactionsTrie": "0xec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3",
|
||||||
"receiptTrie": "0x9593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafa",
|
"receiptTrie": "0x9593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafa",
|
||||||
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
@@ -219,8 +219,8 @@
|
|||||||
"blobGasUsed": "0x00",
|
"blobGasUsed": "0x00",
|
||||||
"excessBlobGas": "0x00",
|
"excessBlobGas": "0x00",
|
||||||
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
"hash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f"
|
"hash": "0x606a39bef40699cba8e82cac36274317a4a9f965db16e67121897e8144dd2ec6"
|
||||||
},
|
},
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{
|
{
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
"depositRequests": [],
|
"depositRequests": [],
|
||||||
"withdrawalRequests": [],
|
"withdrawalRequests": [],
|
||||||
"consolidationRequests": [],
|
"consolidationRequests": [],
|
||||||
"rlp": "0xf902c8f9025fa067315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa061171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0",
|
"rlp": "0xf902c8f9025fa0f87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa00dc49ca54f4370756d0f863551487c2bbc3a327891f9993b10d3985935bc1198a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0",
|
||||||
"blocknumber": "1"
|
"blocknumber": "1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -259,5 +259,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n"
|
"stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0x606a39bef40699cba8e82cac36274317a4a9f965db16e67121897e8144dd2ec6) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500",
|
||||||
"storage": {}
|
"storage": {}
|
||||||
},
|
},
|
||||||
"0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": {
|
"0x0000f90827f1c53a10cb7a02335b175320002935": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
"0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": {
|
"0x0000f90827f1c53a10cb7a02335b175320002935": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
"storage": {
|
"storage": {
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000": "0xe4fb5d47f70d54b4f36777ea4c882cf767f93d8f8170285d97a1b8275dfe4dbb"
|
"0x0000000000000000000000000000000000000000000000000000000000000000": "0xe4fb5d47f70d54b4f36777ea4c882cf767f93d8f8170285d97a1b8275dfe4dbb"
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"requests": [
|
"requests": [
|
||||||
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030100000000000000"
|
"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200405973070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030100000000000000"
|
||||||
],
|
],
|
||||||
"stateRoot": "0xc769f83dbad9b87a209216d18c4b19cb12b61838594a2e8270898438f4e147af",
|
"stateRoot": "0x3db3e963227d69f80461436b60e4c9972a58d17f6219aa65b2ddfdf7da9f6604",
|
||||||
"txRoot": "0x2b790bf82ef7259a0e4513d1b89a77d81e99672ba68758ef2ba3fde32851d023",
|
"txRoot": "0x2b790bf82ef7259a0e4513d1b89a77d81e99672ba68758ef2ba3fde32851d023",
|
||||||
"receiptsRoot": "0x9c8d7a917ecb3ff2566f264abbf39131e51b08b07eb2b69cb46989d79d985593",
|
"receiptsRoot": "0x9c8d7a917ecb3ff2566f264abbf39131e51b08b07eb2b69cb46989d79d985593",
|
||||||
"logsHash": "0x43e31613bfefc1f55d8b3ca2b61f933f3838d523dc11cb5d7ffdd2ecf0ab5d49",
|
"logsHash": "0x43e31613bfefc1f55d8b3ca2b61f933f3838d523dc11cb5d7ffdd2ecf0ab5d49",
|
||||||
|
|||||||
@@ -51,21 +51,21 @@
|
|||||||
"0x40": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7"
|
"0x40": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"0x0c15f14308530b7cdb8460094bbb9cc28b9aaaaa": {
|
"0x00000961ef480eb55e80d19ad83579a64c007002": {
|
||||||
"comment": "This is the runtime bytecode for the Withdrawal Request Smart Contract.",
|
"comment": "This is the runtime bytecode for the Withdrawal Request Smart Contract.",
|
||||||
"nonce": "0x01",
|
"nonce": "0x01",
|
||||||
"balance": "0x00",
|
"balance": "0x00",
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
|
||||||
"storage": {}
|
"storage": {}
|
||||||
},
|
},
|
||||||
"0x00431f263ce400f4455c2dcf564e53007ca4bbbb": {
|
"0x0000bbddc7ce488642fb579f8b00f3a590007251": {
|
||||||
"comment": "Increase the MAX_EFFECTIVE_BALANCE",
|
"comment": "Increase the MAX_EFFECTIVE_BALANCE",
|
||||||
"nonce": "0x01",
|
"nonce": "0x01",
|
||||||
"balance": "0x00",
|
"balance": "0x00",
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
|
||||||
"storage": {}
|
"storage": {}
|
||||||
},
|
},
|
||||||
"0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": {
|
"0x0000f90827f1c53a10cb7a02335b175320002935": {
|
||||||
"nonce": "0x01",
|
"nonce": "0x01",
|
||||||
"balance": "0x00",
|
"balance": "0x00",
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
@@ -84,10 +84,10 @@
|
|||||||
"storage": {}
|
"storage": {}
|
||||||
},
|
},
|
||||||
"0x0000000000000000000000000000000000001000": {
|
"0x0000000000000000000000000000000000001000": {
|
||||||
"comment": "This is a proxy contract that calls 0c15f14308530b7cdb8460094bbb9cc28b9aaaaa ie Withdrawal Request",
|
"comment": "This is a proxy contract that calls 00000961ef480eb55e80d19ad83579a64c007002 ie Withdrawal Request",
|
||||||
"nonce": "0x01",
|
"nonce": "0x01",
|
||||||
"balance": "0xad78ebc5ac62000000",
|
"balance": "0xad78ebc5ac62000000",
|
||||||
"code": "0x6038600060003760006000603860006001730c15f14308530b7cdb8460094bbb9cc28b9aaaaa620f4240f150",
|
"code": "0x60386000600037600060006038600060017300000961ef480eb55e80d19ad83579a64c007002620f4240f150",
|
||||||
"storage": {}
|
"storage": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
"stdout": {
|
"stdout": {
|
||||||
"alloc": {
|
"alloc": {
|
||||||
"0x0000000000000000000000000000000000001000": {
|
"0x0000000000000000000000000000000000001000": {
|
||||||
"code": "0x6038600060003760006000603860006001730c15f14308530b7cdb8460094bbb9cc28b9aaaaa620f4240f150",
|
"code": "0x60386000600037600060006038600060017300000961ef480eb55e80d19ad83579a64c007002620f4240f150",
|
||||||
"balance": "0xad78ebc5ac61ffffff",
|
"balance": "0xad78ebc5ac61ffffff",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
@@ -184,12 +184,12 @@
|
|||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
"0x00431f263ce400f4455c2dcf564e53007ca4bbbb": {
|
"0x0000bbddc7ce488642fb579f8b00f3a590007251": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd",
|
||||||
"balance": "0x0",
|
"balance": "0x0",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
"0x0c15f14308530b7cdb8460094bbb9cc28b9aaaaa": {
|
"0x00000961ef480eb55e80d19ad83579a64c007002": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd",
|
||||||
"storage": {
|
"storage": {
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000001000",
|
"0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000001000",
|
||||||
@@ -198,7 +198,7 @@
|
|||||||
"balance": "0x1",
|
"balance": "0x1",
|
||||||
"nonce": "0x1"
|
"nonce": "0x1"
|
||||||
},
|
},
|
||||||
"0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc": {
|
"0x0000f90827f1c53a10cb7a02335b175320002935": {
|
||||||
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
|
||||||
"storage": {
|
"storage": {
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb"
|
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb"
|
||||||
@@ -217,20 +217,20 @@
|
|||||||
"requests": [
|
"requests": [
|
||||||
"0x0100000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000"
|
"0x0100000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000"
|
||||||
],
|
],
|
||||||
"stateRoot": "0xc7b49e4aef4229962b94ec0a7c83a6fc0b4015f2573b9a85446ed434c823164e",
|
"stateRoot": "0x3c7e1f4b3379b0112968dad5c4abfa297b8ce53ca06ef66c332ed17f41d19922",
|
||||||
"txRoot": "0x0d36638e52999b7beafa00eb94f7ca23139774cd14229c011d0edc1fc66125c9",
|
"txRoot": "0x0d36638e52999b7beafa00eb94f7ca23139774cd14229c011d0edc1fc66125c9",
|
||||||
"receiptsRoot": "0x2af83312a6aa55bd8f169e65eec48f92d6d6dc3398bc038d7ccfab5d9aa26b3f",
|
"receiptsRoot": "0xb188279b8dd5998da7f54224968a83203b9e1496f54d9c0d572a8faddf5dc3f5",
|
||||||
"logsHash": "0xac344ad50aad544ec284bf76ac9b939f93e00f8fe16097a151df14bde2065f83",
|
"logsHash": "0xb30a2575f084f925bf94b37ba4b8c32b87e8380e261a1f407489d46455044dbd",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000",
|
"logsBloom": "0x00000000008000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"receipts": [
|
"receipts": [
|
||||||
{
|
{
|
||||||
"root": "0x",
|
"root": "0x",
|
||||||
"status": "0x1",
|
"status": "0x1",
|
||||||
"cumulativeGasUsed": "0x1e6d4",
|
"cumulativeGasUsed": "0x1e6d4",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000",
|
"logsBloom": "0x00000000008000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"logs": [
|
"logs": [
|
||||||
{
|
{
|
||||||
"address": "0x0c15f14308530b7cdb8460094bbb9cc28b9aaaaa",
|
"address": "0x00000961ef480eb55e80d19ad83579a64c007002",
|
||||||
"topics": [],
|
"topics": [],
|
||||||
"data": "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000",
|
"data": "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000",
|
||||||
"blockNumber": 1,
|
"blockNumber": 1,
|
||||||
|
|||||||
@@ -247,6 +247,10 @@ public class ReferenceTestEnv extends BlockHeader {
|
|||||||
return blockHashes;
|
return blockHashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getParentExcessBlobGas() {
|
||||||
|
return parentExcessBlobGas;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStateTest() {
|
public boolean isStateTest() {
|
||||||
return isStateTest;
|
return isStateTest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
import org.apache.tuweni.bytes.Bytes32;
|
import org.apache.tuweni.bytes.Bytes32;
|
||||||
|
import org.apache.tuweni.bytes.DelegatingBytes;
|
||||||
import org.apache.tuweni.units.bigints.UInt256;
|
import org.apache.tuweni.units.bigints.UInt256;
|
||||||
import org.assertj.core.api.SoftAssertions;
|
import org.assertj.core.api.SoftAssertions;
|
||||||
import org.hyperledger.besu.datatypes.Address;
|
import org.hyperledger.besu.datatypes.Address;
|
||||||
@@ -252,7 +253,7 @@ public class GeneralStateReferenceTestTools {
|
|||||||
if (!storageEntries.isEmpty()) {
|
if (!storageEntries.isEmpty()) {
|
||||||
accountJson.set("storage", storageJson);
|
accountJson.set("storage", storageJson);
|
||||||
}
|
}
|
||||||
worldStateJson.set(account.getAddress().orElse(Address.wrap(Bytes.EMPTY)).toHexString(), accountJson);
|
worldStateJson.set(account.getAddress().map(DelegatingBytes::toHexString).orElse(Bytes.EMPTY.toHexString()), accountJson);
|
||||||
});
|
});
|
||||||
LOG.error("Calculated world state: \n{}", worldStateJson.toPrettyString());
|
LOG.error("Calculated world state: \n{}", worldStateJson.toPrettyString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ dependencies {
|
|||||||
implementation 'io.tmio:tuweni-units'
|
implementation 'io.tmio:tuweni-units'
|
||||||
implementation 'com.google.guava:guava'
|
implementation 'com.google.guava:guava'
|
||||||
|
|
||||||
|
|
||||||
jmh project(':util')
|
jmh project(':util')
|
||||||
|
|
||||||
testImplementation project(':testutil')
|
testImplementation project(':testutil')
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import org.apache.tuweni.units.bigints.UInt256;
|
|||||||
import org.apache.tuweni.units.bigints.UInt64;
|
import org.apache.tuweni.units.bigints.UInt64;
|
||||||
|
|
||||||
abstract class AbstractRLPInput implements RLPInput {
|
abstract class AbstractRLPInput implements RLPInput {
|
||||||
|
|
||||||
private static final String errorMessageSuffix = " (at bytes %d-%d: %s%s[%s]%s%s)";
|
private static final String errorMessageSuffix = " (at bytes %d-%d: %s%s[%s]%s%s)";
|
||||||
|
|
||||||
private final boolean lenient;
|
private final boolean lenient;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.rlp.util.RLPTestUtil;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class RLPTest {
|
public class RLPTest {
|
||||||
@@ -176,7 +177,7 @@ public class RLPTest {
|
|||||||
// ["0x02"]
|
// ["0x02"]
|
||||||
// ]
|
// ]
|
||||||
Bytes validRlp = Bytes.fromHexString("c4c101c102");
|
Bytes validRlp = Bytes.fromHexString("c4c101c102");
|
||||||
RLP.validate(validRlp);
|
Assertions.assertThatCode(() -> RLP.validate(validRlp)).doesNotThrowAnyException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bytes h(final String hex) {
|
private static Bytes h(final String hex) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class BytesTrieSet<E extends Bytes> extends AbstractSet<E> {
|
|||||||
if (leafObject == null) sb.append("null");
|
if (leafObject == null) sb.append("null");
|
||||||
else {
|
else {
|
||||||
sb.append('[');
|
sb.append('[');
|
||||||
System.out.println(leafObject.toHexString());
|
sb.append(leafObject.toHexString());
|
||||||
sb.append(']');
|
sb.append(']');
|
||||||
}
|
}
|
||||||
sb.append(", children=");
|
sb.append(", children=");
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class CancunGasCalculator extends ShanghaiGasCalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The blob gas cost per blob. This is the gas cost for each blob of data that is added to the
|
* The blob gas cost per blob. This is the gas cost for each blob of data that is added to the
|
||||||
* block.
|
* block. 1 << 17 = 131072 = 0x20000
|
||||||
*/
|
*/
|
||||||
private static final long BLOB_GAS_PER_BLOB = 1 << 17;
|
private static final long BLOB_GAS_PER_BLOB = 1 << 17;
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright contributors to 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.operation;
|
|
||||||
|
|
||||||
import org.hyperledger.besu.datatypes.Hash;
|
|
||||||
import org.hyperledger.besu.evm.account.Account;
|
|
||||||
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
|
|
||||||
import org.hyperledger.besu.evm.worldstate.CodeDelegationHelper;
|
|
||||||
|
|
||||||
import org.apache.tuweni.bytes.Bytes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ExtCode* operations treat EOAs with delegated code differently than other operations. This
|
|
||||||
* abstract class contains common methods for this behaviour.
|
|
||||||
*/
|
|
||||||
abstract class AbstractExtCodeOperation extends AbstractOperation {
|
|
||||||
/**
|
|
||||||
* Instantiates a new Abstract operation.
|
|
||||||
*
|
|
||||||
* @param opcode the opcode
|
|
||||||
* @param name the name
|
|
||||||
* @param stackItemsConsumed the stack items consumed
|
|
||||||
* @param stackItemsProduced the stack items produced
|
|
||||||
* @param gasCalculator the gas calculator
|
|
||||||
*/
|
|
||||||
protected AbstractExtCodeOperation(
|
|
||||||
final int opcode,
|
|
||||||
final String name,
|
|
||||||
final int stackItemsConsumed,
|
|
||||||
final int stackItemsProduced,
|
|
||||||
final GasCalculator gasCalculator) {
|
|
||||||
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the code for standard accounts or a special designator for EOAs with delegated code
|
|
||||||
*
|
|
||||||
* @param account The account
|
|
||||||
* @return the code or the special 7702 designator
|
|
||||||
*/
|
|
||||||
protected Bytes getCode(final Account account) {
|
|
||||||
if (account == null) {
|
|
||||||
return Bytes.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.hasDelegatedCode()
|
|
||||||
? CodeDelegationHelper.getCodeDelegationForRead()
|
|
||||||
: account.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the code hash for standard accounts or a special designator for EOAs with delegated
|
|
||||||
* code
|
|
||||||
*
|
|
||||||
* @param account The account
|
|
||||||
* @return the code hash or the hash of the special 7702 designator
|
|
||||||
*/
|
|
||||||
protected Hash getCodeHash(final Account account) {
|
|
||||||
if (account.hasDelegatedCode()) {
|
|
||||||
return Hash.hash(CodeDelegationHelper.getCodeDelegationForRead());
|
|
||||||
}
|
|
||||||
|
|
||||||
return account.getCodeHash();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -57,9 +57,9 @@ public class BlockHashOperation extends AbstractOperation {
|
|||||||
final long currentBlockNumber = blockValues.getNumber();
|
final long currentBlockNumber = blockValues.getNumber();
|
||||||
final BlockHashLookup blockHashLookup = frame.getBlockHashLookup();
|
final BlockHashLookup blockHashLookup = frame.getBlockHashLookup();
|
||||||
|
|
||||||
// If the current block is the genesis block or the sought block is
|
// If the sought block is negative, a future block, the current block, or not in the
|
||||||
// not within the lookback window, zero is returned.
|
// lookback window, zero is returned.
|
||||||
if (currentBlockNumber == 0
|
if (soughtBlock < 0
|
||||||
|| soughtBlock >= currentBlockNumber
|
|| soughtBlock >= currentBlockNumber
|
||||||
|| soughtBlock < (currentBlockNumber - blockHashLookup.getLookback())) {
|
|| soughtBlock < (currentBlockNumber - blockHashLookup.getLookback())) {
|
||||||
frame.pushStackItem(Bytes32.ZERO);
|
frame.pushStackItem(Bytes32.ZERO);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import org.hyperledger.besu.evm.internal.Words;
|
|||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
|
|
||||||
/** The Ext code copy operation. */
|
/** The Ext code copy operation. */
|
||||||
public class ExtCodeCopyOperation extends AbstractExtCodeOperation {
|
public class ExtCodeCopyOperation extends AbstractOperation {
|
||||||
|
|
||||||
/** This is the "code" legacy contracts see when copying code from an EOF contract. */
|
/** This is the "code" legacy contracts see when copying code from an EOF contract. */
|
||||||
public static final Bytes EOF_REPLACEMENT_CODE = Bytes.fromHexString("0xef00");
|
public static final Bytes EOF_REPLACEMENT_CODE = Bytes.fromHexString("0xef00");
|
||||||
@@ -93,8 +93,7 @@ public class ExtCodeCopyOperation extends AbstractExtCodeOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Account account = frame.getWorldUpdater().get(address);
|
final Account account = frame.getWorldUpdater().get(address);
|
||||||
|
final Bytes code = account != null ? account.getCode() : Bytes.EMPTY;
|
||||||
final Bytes code = getCode(account);
|
|
||||||
|
|
||||||
if (enableEIP3540
|
if (enableEIP3540
|
||||||
&& code.size() >= 2
|
&& code.size() >= 2
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import org.hyperledger.besu.evm.internal.Words;
|
|||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
|
|
||||||
/** The Ext code hash operation. */
|
/** The Ext code hash operation. */
|
||||||
public class ExtCodeHashOperation extends AbstractExtCodeOperation {
|
public class ExtCodeHashOperation extends AbstractOperation {
|
||||||
|
|
||||||
// // 0x9dbf3648db8210552e9c4f75c6a1c3057c0ca432043bd648be15fe7be05646f5
|
// // 0x9dbf3648db8210552e9c4f75c6a1c3057c0ca432043bd648be15fe7be05646f5
|
||||||
static final Hash EOF_REPLACEMENT_HASH = Hash.hash(ExtCodeCopyOperation.EOF_REPLACEMENT_CODE);
|
static final Hash EOF_REPLACEMENT_HASH = Hash.hash(ExtCodeCopyOperation.EOF_REPLACEMENT_CODE);
|
||||||
@@ -85,14 +85,14 @@ public class ExtCodeHashOperation extends AbstractExtCodeOperation {
|
|||||||
if (account == null || account.isEmpty()) {
|
if (account == null || account.isEmpty()) {
|
||||||
frame.pushStackItem(Bytes.EMPTY);
|
frame.pushStackItem(Bytes.EMPTY);
|
||||||
} else {
|
} else {
|
||||||
final Bytes code = getCode(account);
|
final Bytes code = account.getCode();
|
||||||
if (enableEIP3540
|
if (enableEIP3540
|
||||||
&& code.size() >= 2
|
&& code.size() >= 2
|
||||||
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
|
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
|
||||||
&& code.get(1) == 0) {
|
&& code.get(1) == 0) {
|
||||||
frame.pushStackItem(EOF_REPLACEMENT_HASH);
|
frame.pushStackItem(EOF_REPLACEMENT_HASH);
|
||||||
} else {
|
} else {
|
||||||
frame.pushStackItem(getCodeHash(account));
|
frame.pushStackItem(account.getCodeHash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new OperationResult(cost, null);
|
return new OperationResult(cost, null);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.hyperledger.besu.evm.internal.Words;
|
|||||||
import org.apache.tuweni.bytes.Bytes;
|
import org.apache.tuweni.bytes.Bytes;
|
||||||
|
|
||||||
/** The Ext code size operation. */
|
/** The Ext code size operation. */
|
||||||
public class ExtCodeSizeOperation extends AbstractExtCodeOperation {
|
public class ExtCodeSizeOperation extends AbstractOperation {
|
||||||
|
|
||||||
static final Bytes EOF_SIZE = Bytes.of(2);
|
static final Bytes EOF_SIZE = Bytes.of(2);
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ public class ExtCodeSizeOperation extends AbstractExtCodeOperation {
|
|||||||
if (account == null) {
|
if (account == null) {
|
||||||
codeSize = Bytes.EMPTY;
|
codeSize = Bytes.EMPTY;
|
||||||
} else {
|
} else {
|
||||||
final Bytes code = getCode(account);
|
final Bytes code = account.getCode();
|
||||||
if (enableEIP3540
|
if (enableEIP3540
|
||||||
&& code.size() >= 2
|
&& code.size() >= 2
|
||||||
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
|
&& code.get(0) == EOFLayout.EOF_PREFIX_BYTE
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user