-
Notifications
You must be signed in to change notification settings - Fork 406
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
Add support for eth68 #4866
Changes from 19 commits
0299694
b734ab5
692ef07
e8b67ee
c8059ad
f5feb4e
a7560b1
d7097d9
a0ccb0b
cfbc257
260d7ee
f8e1f33
ba8f74d
f0b3442
5a10857
a2a1f2f
b892322
5881a23
9b349ad
e123c19
e84f311
2c3e0a2
81f6d18
77701f6
3a15b7f
648e156
89991e8
ae32d99
a82d574
63ddc23
b04541f
dc84be6
9227f4f
879e1a7
7793937
ac14f58
7ae7424
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not do the whole comparision: _handler.Should().BeEquivalentTo(expectedHandler)? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
} | ||
|
||
[TestCase(0)] | ||
[TestCase(1)] | ||
[TestCase(2)] | ||
[TestCase(100)] | ||
public void Can_handle_NewPooledTransactions_message(int txCount) | ||
{ | ||
GenerateLists(txCount, out List<TxType> types, out List<int> sizes, out List<Keccak> hashes); | ||
|
||
var msg = new NewPooledTransactionHashesMessage68(types, sizes, hashes); | ||
|
||
HandleIncomingStatusMessage(); | ||
HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes); | ||
_pooledTxsRequestor.Received().RequestTransactionsEth68(Arg.Any<Action<GetPooledTransactionsMessage>>(), | ||
Arg.Any<IReadOnlyList<Keccak>>(), Arg.Any<IReadOnlyList<int>>(), Arg.Any<IReadOnlyList<TxType>>()); | ||
} | ||
|
||
[TestCase(true)] | ||
[TestCase(false)] | ||
public void Should_throw_when_sizes_doesnt_match(bool removeSize) | ||
{ | ||
GenerateLists(4, out List<TxType> 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[] { tx.Type }, | ||
new[] { txDecoder.GetLength(tx, RlpBehaviors.None) }, new[] { tx.Hash }); | ||
|
||
HandleIncomingStatusMessage(); | ||
|
||
HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes); | ||
_pooledTxsRequestor.Received().RequestTransactionsEth68(Arg.Any<Action<GetPooledTransactionsMessage>>(), | ||
Arg.Any<IReadOnlyList<Keccak>>(), Arg.Any<IReadOnlyList<int>>(), Arg.Any<IReadOnlyList<TxType>>()); | ||
} | ||
|
||
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<TxType> 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(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,64 @@ | ||
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, 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)); | ||
} | ||
|
||
[Test] | ||
public void Empty_to_string() | ||
{ | ||
NewPooledTransactionHashesMessage68 message | ||
= new(new TxType[] { }, new int[] { }, new Keccak[] { }); | ||
_ = message.ToString(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if just simple
int? Size {get;set;}
wouldn't be better.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to pass ITranzactionSizeCalculator to make it lazy initialized
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could initialize it to
null
and set it from outside when ready/needed.