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

Add support for eth68 #4866

Merged
merged 37 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0299694
eth68 implementation
deffrian Nov 3, 2022
b734ab5
test
deffrian Nov 3, 2022
692ef07
refactor serializer
marcindsobczak Nov 4, 2022
e8b67ee
change typesSize back
marcindsobczak Nov 4, 2022
c8059ad
Tests and enable capability
deffrian Nov 4, 2022
f5feb4e
serializer tests
deffrian Nov 5, 2022
a7560b1
Fix whitespaces
deffrian Nov 6, 2022
d7097d9
fix whitespaces
deffrian Nov 6, 2022
a0ccb0b
Merge branch 'master' into feature/eth68
deffrian Nov 9, 2022
cfbc257
Refactor
deffrian Nov 9, 2022
260d7ee
Fix serialization & peer drop
deffrian Nov 10, 2022
f8e1f33
RequestTransactions68
deffrian Nov 11, 2022
ba8f74d
Metrics & logs
deffrian Nov 11, 2022
f0b3442
Reduce paket max size
deffrian Nov 12, 2022
5a10857
Calculate length properly
deffrian Nov 14, 2022
a2a1f2f
fix tests & length
deffrian Nov 14, 2022
b892322
huge transaction test
deffrian Nov 14, 2022
5881a23
fix spaces
deffrian Nov 14, 2022
9b349ad
Make size calculated once per transaction
deffrian Nov 17, 2022
e123c19
Refactor & optimizations
deffrian Nov 20, 2022
e84f311
Fix hive tests
deffrian Nov 21, 2022
2c3e0a2
Merge branch 'master' into feature/eth68
deffrian Nov 22, 2022
81f6d18
Copyright fix
deffrian Nov 22, 2022
77701f6
ubuntu 20.04 workflow
deffrian Nov 22, 2022
3a15b7f
Merge branch 'master' into feature/eth68
deffrian Nov 22, 2022
648e156
Revert "ubuntu 20.04 workflow"
deffrian Nov 22, 2022
89991e8
Revert "Revert "ubuntu 20.04 workflow""
deffrian Nov 22, 2022
ae32d99
Remove metrics & for loop
deffrian Nov 29, 2022
a82d574
Remove test & RequestTransactionsEth68
deffrian Dec 1, 2022
63ddc23
EncodeList implementation
deffrian Dec 1, 2022
b04541f
Fix test
deffrian Dec 1, 2022
dc84be6
Revert renaming
deffrian Dec 2, 2022
9227f4f
Rename write
deffrian Dec 2, 2022
879e1a7
Remove Request68
deffrian Dec 2, 2022
7793937
Fix run-nethermind-tests.yml
deffrian Dec 14, 2022
ac14f58
Fix run-nethermind-tests.yml
deffrian Dec 14, 2022
7ae7424
Merge branch 'master' into feature/eth68
deffrian Dec 14, 2022
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.AccountAbstraction.Network;
using Nethermind.Core;
Expand Down
20 changes: 19 additions & 1 deletion src/Nethermind/Nethermind.Core/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ public class Transaction
/// <remarks>Used for sorting in edge cases.</remarks>
public ulong PoolIndex { get; set; }

private int? _size = null;
/// <summary>
/// Encoded transaction length
/// </summary>
public int GetLength(ITransactionSizeCalculator sizeCalculator)
{
return _size ??= sizeCalculator.GetLength(this);
}

public string ToShortString()
{
string gasPriceString =
Expand Down Expand Up @@ -102,7 +111,16 @@ public string ToString(string indent)
public class GeneratedTransaction : Transaction { }

/// <summary>
/// System transaction that is to be executed by the node without including in the block.
/// System transaction that is to be executed by the node without including in the block.
/// </summary>
public class SystemTransaction : Transaction { }

/// <summary>
/// Used inside Transaction::GetSize to calculate encoded transaction size
/// </summary>
/// <remarks>Created because of cyclic dependencies between Core and Rlp modules</remarks>
public interface ITransactionSizeCalculator
{
int GetLength(Transaction tx);
}
}
9 changes: 8 additions & 1 deletion src/Nethermind/Nethermind.Crypto/KeccakRlpStream.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Nethermind.Core.Crypto;
using Nethermind.Serialization.Rlp;
Expand All @@ -28,6 +30,11 @@ public override void Write(Span<byte> bytesToWrite)
_keccakHash.Update(bytesToWrite, 0, bytesToWrite.Length);
}

public override void Write(IReadOnlyList<byte> bytesToWrite)
{
_keccakHash.Update(bytesToWrite.ToArray(), 0, bytesToWrite.Count);
}

public override void WriteByte(byte byteToWrite)
{
_keccakHash.Update(MemoryMarshal.CreateSpan(ref byteToWrite, 1), 0, 1);
Expand Down
3 changes: 2 additions & 1 deletion src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,9 @@ private async Task Initialize(CancellationToken cancellationToken)
// we can't add eth67 capability as default, because it needs snap protocol for syncing (GetNodeData is
// no longer available). Eth67 should be added if snap is enabled OR sync is finished
_api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Eth, 67));
_api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Eth, 68));
}
else if (_logger.IsDebug) _logger.Debug("Skipped enabling eth67 capability");
else if (_logger.IsDebug) _logger.Debug("Skipped enabling eth67 & eth68 capabilities");

if (_syncConfig.SnapSync && !stateSyncFinished)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Network.Enr/NodeRecordSigner.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System.Net;
using Nethermind.Core.Crypto;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ public SerializationBuilder WithEth66()
.With(new Network.P2P.Subprotocols.Eth.V66.Messages.ReceiptsMessageSerializer(new ReceiptsMessageSerializer(MainnetSpecProvider.Instance)));
}

public SerializationBuilder WithEth68()
{
return WithEth66()
.With(new Network.P2P.Subprotocols.Eth.V68.Messages.NewPooledTransactionHashesMessageSerializer());
}

public SerializationBuilder WithDiscovery(PrivateKey privateKey)
{
Ecdsa ecdsa = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using System.Net;
using DotNetty.Buffers;
using FluentAssertions;
using Nethermind.Consensus;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Core.Timers;
using Nethermind.Logging;
using Nethermind.Network.P2P;
using Nethermind.Network.P2P.Subprotocols;
using Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages;
using Nethermind.Network.P2P.Subprotocols.Eth.V65;
using Nethermind.Network.P2P.Subprotocols.Eth.V66.Messages;
using Nethermind.Network.P2P.Subprotocols.Eth.V68;
using Nethermind.Network.P2P.Subprotocols.Eth.V68.Messages;
using Nethermind.Network.Rlpx;
using Nethermind.Network.Test.Builders;
using Nethermind.Serialization.Rlp;
using Nethermind.Stats;
using Nethermind.Stats.Model;
using Nethermind.Synchronization;
using Nethermind.TxPool;
using NSubstitute;
using NUnit.Framework;

namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V68;

public class Eth68ProtocolHandlerTests
{
private ISession _session;
private IMessageSerializationService _svc;
private ISyncServer _syncManager;
private ITxPool _transactionPool;
private IPooledTxsRequestor _pooledTxsRequestor;
private IGossipPolicy _gossipPolicy;
private ISpecProvider _specProvider;
private Block _genesisBlock;
private Eth68ProtocolHandler _handler;

[SetUp]
public void Setup()
{
_svc = Build.A.SerializationService().WithEth68().TestObject;

NetworkDiagTracer.IsEnabled = true;

_session = Substitute.For<ISession>();
Node node = new(TestItem.PublicKeyA, new IPEndPoint(IPAddress.Broadcast, 30303));
_session.Node.Returns(node);
_syncManager = Substitute.For<ISyncServer>();
_transactionPool = Substitute.For<ITxPool>();
_pooledTxsRequestor = Substitute.For<IPooledTxsRequestor>();
_specProvider = Substitute.For<ISpecProvider>();
_gossipPolicy = Substitute.For<IGossipPolicy>();
_genesisBlock = Build.A.Block.Genesis.TestObject;
_syncManager.Head.Returns(_genesisBlock.Header);
_syncManager.Genesis.Returns(_genesisBlock.Header);
ITimerFactory timerFactory = Substitute.For<ITimerFactory>();
_handler = new Eth68ProtocolHandler(
_session,
_svc,
new NodeStatsManager(timerFactory, LimboLogs.Instance),
_syncManager,
_transactionPool,
_pooledTxsRequestor,
_gossipPolicy,
_specProvider,
LimboLogs.Instance);
_handler.Init();
}

[TearDown]
public void TearDown()
{
_handler.Dispose();
}

[Test]
public void Metadata_correct()
{
_handler.ProtocolCode.Should().Be("eth");
_handler.Name.Should().Be("eth68");
_handler.ProtocolVersion.Should().Be(68);
_handler.MessageIdSpaceSize.Should().Be(17);
_handler.IncludeInTxPool.Should().BeTrue();
_handler.ClientId.Should().Be(_session.Node?.ClientId);
_handler.HeadHash.Should().BeNull();
_handler.HeadNumber.Should().Be(0);
Comment on lines +88 to +95
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do the whole comparision:

_handler.Should().BeEquivalentTo(expectedHandler)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is an updated copy-paste of metadata tests for older protocols. Purpose of this test is to check if metadata are correct and it is doing it perfectly. If we create another instance o Eth68ProtocolHandler and compare equivalence with _handler, we will still don't know if these details are correct in both or wrong in both of them. It is not overwritable from the outside, so no way to ensure correctness of expectedHandler

}

[TestCase(0)]
[TestCase(1)]
[TestCase(2)]
[TestCase(100)]
public void Can_handle_NewPooledTransactions_message(int txCount)
{
GenerateLists(txCount, out List<byte> types, out List<int> sizes, out List<Keccak> hashes);

var msg = new NewPooledTransactionHashesMessage68(types, sizes, hashes);

HandleIncomingStatusMessage();
HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes);
_pooledTxsRequestor.Received().RequestTransactionsEth66(Arg.Any<Action<GetPooledTransactionsMessage>>(),
Arg.Any<IReadOnlyList<Keccak>>());
}

[TestCase(true)]
[TestCase(false)]
public void Should_throw_when_sizes_doesnt_match(bool removeSize)
{
GenerateLists(4, out List<byte> types, out List<int> sizes, out List<Keccak> hashes);

if (removeSize)
{
sizes.RemoveAt(sizes.Count - 1);
}
else
{
types.RemoveAt(sizes.Count - 1);
}

var msg = new NewPooledTransactionHashesMessage68(types, sizes, hashes);

HandleIncomingStatusMessage();
Action action = () => HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes);
action.Should().Throw<SubprotocolException>();
}

[Test]
public void Should_process_huge_transaction()
{
Transaction tx = Build.A.Transaction.WithType(TxType.EIP1559).WithData(new byte[2 * 1024 * 1024])
.WithHash(TestItem.KeccakA).TestObject;

TxDecoder txDecoder = new();

var msg = new NewPooledTransactionHashesMessage68(new[] { (byte)tx.Type },
new[] { txDecoder.GetLength(tx, RlpBehaviors.None) }, new[] { tx.Hash });

HandleIncomingStatusMessage();

HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes);
_pooledTxsRequestor.Received().RequestTransactionsEth66(Arg.Any<Action<GetPooledTransactionsMessage>>(),
Arg.Any<IReadOnlyList<Keccak>>());
}

private void HandleIncomingStatusMessage()
{
var statusMsg = new StatusMessage();
statusMsg.GenesisHash = _genesisBlock.Hash;
statusMsg.BestHash = _genesisBlock.Hash;

IByteBuffer statusPacket = _svc.ZeroSerialize(statusMsg);
statusPacket.ReadByte();
_handler.HandleMessage(new ZeroPacket(statusPacket) { PacketType = 0 });
}

private void HandleZeroMessage<T>(T msg, byte messageCode) where T : MessageBase
{
IByteBuffer getBlockHeadersPacket = _svc.ZeroSerialize(msg);
getBlockHeadersPacket.ReadByte();
_handler.HandleMessage(new ZeroPacket(getBlockHeadersPacket) { PacketType = messageCode });
}

private void GenerateLists(int txCount, out List<byte> types, out List<int> sizes, out List<Keccak> hashes)
{
TxDecoder txDecoder = new();
types = new();
sizes = new();
hashes = new();

for (int i = 0; i < txCount; ++i)
{
Transaction tx = Build.A.Transaction.WithType((TxType)(i % 3)).WithData(new byte[i])
.WithHash(i % 2 == 0 ? TestItem.KeccakA : TestItem.KeccakB).TestObject;

types.Add((byte)tx.Type);
sizes.Add(txDecoder.GetLength(tx, RlpBehaviors.None));
hashes.Add(tx.Hash);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Linq;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Test.Builders;
using Nethermind.Network.P2P.Subprotocols.Eth.V68.Messages;
using NUnit.Framework;

namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V68;

[TestFixture, Parallelizable(ParallelScope.All)]
public class NewPooledTransactionHashesMessageSerializerTests
{
private static void Test(TxType[] types, int[] sizes, Keccak[] hashes, string expected = null)
{
NewPooledTransactionHashesMessage68 message = new(types.Select(t => (byte)t).ToList(), sizes, hashes);
NewPooledTransactionHashesMessageSerializer serializer = new();

SerializerTester.TestZero(serializer, message, expected);
}

[Test]
public void Roundtrip()
{
TxType[] types = { TxType.Legacy, TxType.AccessList, TxType.EIP1559 };
int[] sizes = { 5, 10, 1500 };
Keccak[] hashes = { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC };
Test(types, sizes, hashes);
}

[Test]
public void Empty_serialization()
{
TxType[] types = { };
int[] sizes = { };
Keccak[] hashes = { };
Test(types, sizes, hashes, "c380c0c0");
}

[Test]
public void Empty_hashes_serialization()
{
TxType[] types = { TxType.EIP1559 };
int[] sizes = { 10 };
Keccak[] hashes = { };
Test(types, sizes, hashes, "c402c10ac0");
}

[Test]
public void Non_empty_serialization()
{
TxType[] types = { TxType.AccessList };
int[] sizes = { 2 };
Keccak[] hashes = { TestItem.KeccakA };
Test(types, sizes, hashes,
"e5" + "01" + "c102" + "e1a0" + TestItem.KeccakA.ToString(false));
}

}
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Network/Metrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ public static class Metrics
[Description("Number of eth.65 NewPooledTransactionHashes messages sent")]
public static long Eth65NewPooledTransactionHashesSent { get; set; }

[Description("Number of eth.68 NewPooledTransactionHashes messages received")]
public static long Eth68NewPooledTransactionHashesReceived { get; set; }

[Description("Number of eth.68 NewPooledTransactionHashes messages sent")]
public static long Eth68NewPooledTransactionHashesSent { get; set; }

[Description("Number of eth.65 GetPooledTransactions messages received")]
public static long Eth65GetPooledTransactionsReceived { get; set; }

Expand Down
15 changes: 15 additions & 0 deletions src/Nethermind/Nethermind.Network/P2P/NettyRlpStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using DotNetty.Buffers;
using Nethermind.Serialization.Rlp;

Expand Down Expand Up @@ -31,6 +32,20 @@ public override void Write(Span<byte> bytesToWrite)
_buffer.SetWriterIndex(newWriterIndex);
}

public override void Write(IReadOnlyList<byte> bytesToWrite)
{
_buffer.EnsureWritable(bytesToWrite.Count, true);
Span<byte> target =
_buffer.Array.AsSpan(_buffer.ArrayOffset + _buffer.WriterIndex, bytesToWrite.Count);
for (int i = 0; i < bytesToWrite.Count; ++i)
{
target[i] = bytesToWrite[i];
}

int newWriterIndex = _buffer.WriterIndex + bytesToWrite.Count;
_buffer.SetWriterIndex(newWriterIndex);
}

public override void WriteByte(byte byteToWrite)
{
_buffer.EnsureWritable(1, true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
Expand Down
Loading