Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feature: Add support for block validation (flashbots_validateBuilderSubmissionV3) #7335

Open
wants to merge 56 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d33add6
add init code for block validation
rjnrohit Aug 16, 2024
9eb6f70
format files
rjnrohit Aug 16, 2024
ae4357f
verify blobs
rjnrohit Aug 27, 2024
346330d
create block processor
rjnrohit Sep 2, 2024
b802039
add modal validate payload
rjnrohit Sep 4, 2024
6ad5909
format files
rjnrohit Sep 4, 2024
3cf82fe
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 4, 2024
256da82
add hook step
rjnrohit Sep 5, 2024
a749b8e
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 5, 2024
09b46b4
add config
rjnrohit Sep 5, 2024
621e297
format files
rjnrohit Sep 5, 2024
ffc25f0
address PR comments
rjnrohit Sep 12, 2024
1bebf60
Hookup BlockValidation plugin in Nethermind.Runner
LukaszRozmej Sep 12, 2024
570dce0
Update Fast Sync configuration in Nethermind repository (#7401)
core-repository-dispatch-app[bot] Sep 8, 2024
bec7a5d
Feature/geth like system tx (#7252)
LukaszRozmej Sep 9, 2024
8b8cd01
Heuristic tx censorship detection (#7259)
Arindam2407 Sep 10, 2024
69e36dd
Refactor `TxValidator` (#7386)
emlautarom1 Sep 10, 2024
17533eb
Moved BlockProductionTimeout to config, increased BlockProductionTime…
MarekM25 Sep 10, 2024
c1f9455
Reduce memory use during Archive Sync (#7407)
benaadams Sep 11, 2024
5aebe9b
Update Supported Networks in Readme (#7412)
MarekM25 Sep 11, 2024
37b9fb4
Change Windows native Allocator (#7418)
benaadams Sep 11, 2024
4a17264
Fast address equals (#7417)
benaadams Sep 11, 2024
413a5b3
Reduce backlog threshold for GC (#7415)
benaadams Sep 11, 2024
bb3753d
Bump unstable to 1.29.0 (#7416)
kamilchodola Sep 11, 2024
4373e5a
enable flashBots module
rjnrohit Sep 12, 2024
a73b41a
format files
rjnrohit Sep 12, 2024
cfe14f2
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 12, 2024
71e03eb
rename blockValidation -> flashbots
rjnrohit Sep 13, 2024
9f1bf85
rename params
rjnrohit Sep 13, 2024
d203d5e
revert holesky.cfg
rjnrohit Sep 13, 2024
1d7c272
add json required
rjnrohit Sep 19, 2024
2e4775c
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 19, 2024
0c15eea
fix parameter serialization
rjnrohit Sep 23, 2024
ea60068
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 23, 2024
558a425
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Sep 24, 2024
4eeeb9f
Add initial tests
rjnrohit Sep 26, 2024
c739854
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Oct 10, 2024
3bbce1f
format files
rjnrohit Oct 10, 2024
82d4747
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Oct 11, 2024
b9b2008
dummy
rjnrohit Oct 24, 2024
214b5f0
dummy
rjnrohit Oct 24, 2024
175a692
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Oct 28, 2024
a3b0550
fix balance check
rjnrohit Oct 30, 2024
b585e52
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Nov 6, 2024
a0361cf
fix small errors
rjnrohit Nov 11, 2024
2e75139
format files
rjnrohit Nov 11, 2024
a4bf424
Merge remote-tracking branch 'origin' into feature/flashbots_endpoints
rjnrohit Nov 11, 2024
14850e5
dummy
rjnrohit Nov 21, 2024
ee73d09
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Dec 10, 2024
65a969f
remove default account
rjnrohit Dec 17, 2024
568dd5d
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Dec 17, 2024
3ce68ee
dummy commit
rjnrohit Dec 19, 2024
6a9762d
add prewarmer
rjnrohit Dec 23, 2024
6640aca
revert dummy changes
rjnrohit Dec 23, 2024
b73c96b
remove using
rjnrohit Dec 23, 2024
b569844
Merge branch 'master' into feature/flashbots_endpoints
rjnrohit Dec 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/nethermind-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
- Nethermind.EthStats.Test
- Nethermind.Evm.Test
- Nethermind.Facade.Test
- Nethermind.Flashbots.Test
- Nethermind.HealthChecks.Test
- Nethermind.Hive.Test
- Nethermind.JsonRpc.Test
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace Nethermind.Api.Extensions;

public class PluginConfig : IPluginConfig
{
public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "Shutter", "Taiko", "AuRaMerge", "Merge", "MEV", "HealthChecks", "Hive" };
public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "Shutter", "Taiko", "AuRaMerge", "Merge", "Flashbots", "MEV", "HealthChecks", "Hive" };
}
173 changes: 173 additions & 0 deletions src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Threading.Tasks;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Synchronization;
using Nethermind.Consensus;
using Nethermind.Consensus.Processing;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Blockchain;
using Nethermind.Crypto;
using Nethermind.Db;
using Nethermind.Flashbots;
using Nethermind.Flashbots.Handlers;
using Nethermind.Flashbots.Modules.Flashbots;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Merge.Plugin;
using Nethermind.Specs;
using Nethermind.Specs.ChainSpecStyle;
using Nethermind.Specs.Forks;
using NUnit.Framework;

namespace Nethermind.Flasbots.Test;

public partial class FlashbotsModuleTests
{
TestKeyAndAddress? TestKeysAndAddress;

[SetUp]
public void SetUp()
{
TestKeysAndAddress = new TestKeyAndAddress();
}

internal class TestKeyAndAddress
{
public PrivateKey PrivateKey = new PrivateKey("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291");
public Address TestAddr;

public PrivateKey TestValidatorKey = new PrivateKey("28c3cd61b687fdd03488e167a5d84f50269df2a4c29a2cfb1390903aa775c5d0");
public Address TestValidatorAddr;

public PrivateKey TestBuilderKey = new PrivateKey("0bfbbbc68fefd990e61ba645efb84e0a62e94d5fff02c9b1da8eb45fea32b4e0");
public Address TestBuilderAddr;

public UInt256 TestBalance = UInt256.Parse("2000000000000000000");
public byte[] logCode = Bytes.FromHexString("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00");

public UInt256 BaseInitialFee = 1000000000;
public TestKeyAndAddress()
{
TestAddr = PrivateKey.Address;
TestValidatorAddr = TestValidatorKey.Address;
TestBuilderAddr = TestBuilderKey.Address;
}
}

protected virtual MergeTestBlockChain CreateBaseBlockChain(
IFlashbotsConfig flashbotsConfig,
ILogManager? logManager = null)
{
return new MergeTestBlockChain(flashbotsConfig, logManager);
}

protected async Task<MergeTestBlockChain> CreateBlockChain(
IReleaseSpec? releaseSpec = null,
IFlashbotsConfig? flashbotsConfig = null,
ILogManager? logManager = null)
=> await CreateBaseBlockChain(flashbotsConfig ?? new FlashbotsConfig(), logManager).Build(new TestSingleReleaseSpecProvider(releaseSpec ?? London.Instance));

private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv)
{
return new FlashbotsRpcModule(
new ValidateSubmissionHandler(

Check failure on line 81 in src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs

View workflow job for this annotation

GitHub Actions / Build (debug, Nethermind)

There is no argument given that corresponds to the required parameter 'logManager' of 'ValidateSubmissionHandler.ValidateSubmissionHandler(IHeaderValidator, IBlockValidator, ReadOnlyTxProcessingEnv, ReadOnlyTxProcessingEnvFactory, ILogManager, ISpecProvider, IFlashbotsConfig)'

Check failure on line 81 in src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs

View workflow job for this annotation

GitHub Actions / Build (debug, Nethermind)

There is no argument given that corresponds to the required parameter 'logManager' of 'ValidateSubmissionHandler.ValidateSubmissionHandler(IHeaderValidator, IBlockValidator, ReadOnlyTxProcessingEnv, ReadOnlyTxProcessingEnvFactory, ILogManager, ISpecProvider, IFlashbotsConfig)'
chain.HeaderValidator,
chain.BlockValidator,
readOnlyTxProcessingEnv,
chain.FlashbotsConfig
)
);
}

public class MergeTestBlockChain : TestBlockchain
{
public IFlashbotsConfig FlashbotsConfig;

public IMergeConfig MergeConfig;

public IWithdrawalProcessor? WithdrawalProcessor { get; set; }

public ReadOnlyTxProcessingEnv ReadOnlyTxProcessingEnv { get; set; }

public MergeTestBlockChain(IFlashbotsConfig flashbotsConfig, ILogManager? logManager = null)
{
FlashbotsConfig = flashbotsConfig;
MergeConfig = new MergeConfig() { TerminalTotalDifficulty = "0" };
LogManager = logManager ?? LogManager;
}

public sealed override ILogManager LogManager { get; set; } = LimboLogs.Instance;

public ReadOnlyTxProcessingEnv CreateReadOnlyTxProcessingEnv()
{
ReadOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv(
WorldStateManager,
BlockTree,
SpecProvider,
LogManager
);
return ReadOnlyTxProcessingEnv;
}

protected override IBlockProcessor CreateBlockProcessor()
{
BlockValidator = CreateBlockValidator();
WithdrawalProcessor = new WithdrawalProcessor(State, LogManager);
IBlockProcessor prcessor = new BlockProcessor(
SpecProvider,
BlockValidator,
NoBlockRewards.Instance,
new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State),
State,
ReceiptStorage,
TxProcessor,
new BeaconBlockRootHandler(TxProcessor, State),
new BlockhashStore(SpecProvider, State),
LogManager,
WithdrawalProcessor
);

return prcessor;
}

protected IBlockValidator CreateBlockValidator()
{
PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, new ChainSpec() { Genesis = Core.Test.Builders.Build.A.Block.WithDifficulty(0).TestObject }, LogManager);
ISealValidator SealValidator = new MergeSealValidator(PoSSwitcher, Always.Valid);
HeaderValidator = new MergeHeaderValidator(
PoSSwitcher,
new HeaderValidator(BlockTree, SealValidator, SpecProvider, LogManager),
BlockTree,
SpecProvider,
SealValidator,
LogManager
);

return new BlockValidator(
new TxValidator(SpecProvider.ChainId),
HeaderValidator,
Always.Valid,
SpecProvider,
LogManager
);
}

protected override async Task<TestBlockchain> Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true)
{
TestBlockchain chain = await base.Build(specProvider, initialValues);
return chain;
}

public async Task<MergeTestBlockChain> Build(ISpecProvider? specProvider = null) =>
(MergeTestBlockChain)await Build(specProvider, null);

}
}
140 changes: 140 additions & 0 deletions src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Consensus.Processing;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Flashbots.Modules.Flashbots;
using Nethermind.Int256;
using Nethermind.JsonRpc;
using Nethermind.JsonRpc.Test;
using Nethermind.Merge.Plugin.Data;
using Nethermind.Specs.Forks;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.Flasbots.Test;

public partial class FlashbotsModuleTests
{
private static readonly DateTime Timestamp = DateTimeOffset.FromUnixTimeSeconds(1000).UtcDateTime;
private ITimestamper Timestamper { get; } = new ManualTimestamper(Timestamp);

[Test]
public virtual async Task TestValidateBuilderSubmissionV3()
{
using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance);
ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv();
IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnv);
BlockHeader currentHeader = chain.BlockTree.Head.Header;
IWorldState State = chain.State;

UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr);

Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(new Address("0x16")).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject;
chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None);

Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject;
chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None);

UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec());

Transaction tx3 = Build.A.Transaction.WithNonce(nonce + 2).WithValue(10).WithGasLimit(21000).WithValue(baseFee).Signed(TestKeysAndAddress.PrivateKey).TestObject;
chain.TxPool.SubmitTx(tx3, TxPool.TxHandlingOptions.None);

Withdrawal[] withdrawals = [
Build.A.Withdrawal.WithIndex(0).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject,
Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject
];

ulong timestamp = Timestamper.UnixTime.Seconds;
Hash256 prevRandao = Keccak.Zero;

var payloadAttrs = new
{
timestamp = timestamp.ToHexString(true),
prevRandao,
suggestedFeeRecipient = TestKeysAndAddress.TestAddr.ToString(),
withdrawals,
parentBeaconBLockRoot = Keccak.Zero
};

string?[] @params = new string?[]
{
chain.JsonSerializer.Serialize(new {
headBlockHash = currentHeader.Hash.ToString(),
safeBlockHash = currentHeader.Hash.ToString(),
finalizedBlockHash = currentHeader.Hash.ToString(),
}), chain.JsonSerializer.Serialize(payloadAttrs)
};
string expectedPayloadId = "0x774c6aff527bbc68";

string response = await RpcTest.TestSerializedRequest(rpc, "engine_forkchoiceUpdatedV3", @params!);
JsonRpcSuccessResponse? successResponse = chain.JsonSerializer.Deserialize<JsonRpcSuccessResponse>(response);

successResponse.Should().NotBeNull();
response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse
{
Id = successResponse.Id,
Result = new ForkchoiceUpdatedV1Result
{
PayloadId = expectedPayloadId,
PayloadStatus = new PayloadStatusV1
{
LatestValidHash = new("0xd7e58364f16b4a329b959b166f9c32323cb135669335db5dadd0344568f8dc9a"),
Status = PayloadStatus.Valid,
ValidationError = null
}
}
}));

Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26");
string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154";

Block block = new(
new(
currentHeader.Hash,
Keccak.OfAnEmptySequenceRlp,
TestKeysAndAddress.TestAddr,
UInt256.Zero,
1,
chain.BlockTree.Head!.GasLimit,
timestamp,
Bytes.FromHexString("0x4e65746865726d696e64") // Nethermind
)
{
BlobGasUsed = 0,
ExcessBlobGas = 0,
BaseFeePerGas = 0,
Bloom = Bloom.Empty,
GasUsed = 0,
Hash = expectedBlockHash,
MixHash = prevRandao,
ParentBeaconBlockRoot = Keccak.Zero,
ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!,
StateRoot = new(stateRoot),
},
Array.Empty<Transaction>(),
Array.Empty<BlockHeader>(),
withdrawals
);

GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block));

response = await RpcTest.TestSerializedRequest(rpc, "engine_getPayloadV3", expectedPayloadId);
successResponse = chain.JsonSerializer.Deserialize<JsonRpcSuccessResponse>(response);

successResponse.Should().NotBeNull();
response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse
{
Id = successResponse.Id,
Result = expectedPayload
}));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Nullable>annotations</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Nethermind.JsonRpc.Test\Nethermind.JsonRpc.Test.csproj" />
<ProjectReference Include="..\Nethermind.Consensus\Nethermind.Consensus.csproj" />
<ProjectReference Include="..\Nethermind.Core.Test\Nethermind.Core.Test.csproj" />
<ProjectReference Include="..\Nethermind.Merge.Plugin.Test\Nethermind.Merge.Plugin.Test.csproj" />
<ProjectReference Include="..\Nethermind.Flashbots\Nethermind.Flashbots.csproj" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Int256;

namespace Nethermind.Flashbots.Data;

public class BidTrace(
ulong slot,
Hash256 blockHash,
PublicKey builderPublicKey,
PublicKey proposerPublicKey,
Address proposerFeeRecipient,
long gasLimit,
long gasUsed,
UInt256 value)
{
public ulong Slot { get; } = slot;
public required Hash256 ParentHash { get; set; }
public Hash256 BlockHash { get; } = blockHash;
public PublicKey BuilderPublicKey { get; } = builderPublicKey;
public PublicKey ProposerPublicKey { get; } = proposerPublicKey;
public Address ProposerFeeRecipient { get; } = proposerFeeRecipient;
public long GasLimit { get; } = gasLimit;
public long GasUsed { get; } = gasUsed;
public UInt256 Value { get; } = value;
}
Loading
Loading