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

Remove the need of reflection of p2p message (de)serialization #1195

Merged
merged 7 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions NBitcoin/ConsensusFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,50 @@ public bool TryCreateNew<T>(out T result) where T : IBitcoinSerializable
return success;
}

public virtual Payload CreatePayload(string command)
{
return command switch
{
"inv" => new InvPayload(),
"tx" => new TxPayload(),
"getdata" => new GetDataPayload(),
"headers" => new HeadersPayload(),
"block" => new BlockPayload(),
#if !NOSOCKET
"addr" => new AddrPayload(),
"addrv2" => new AddrV2Payload(),
"version" => new VersionPayload(),
#endif
"ping" => new PingPayload(),
"pong" => new PongPayload(),
"getaddr" => new GetAddrPayload(),
"blocktxn" => new BlockTxnPayload(),
"cmpctblock" => new CmpctBlockPayload(),
"cfilter" => new CompactFilterPayload(),
"cfcheckpt" => new CompactFilterCheckPointPayload(),
"cfheaders" => new CompactFilterHeadersPayload(),
"feefilter" => new FeeFilterPayload(),
"filteradd" => new FilterAddPayload(),
"filterload" => new FilterLoadPayload(),
"getblocktxn" => new GetBlockTxnPayload(),
"getblocks" => new GetBlocksPayload(),
"getcfilters" => new GetCompactFiltersPayload(),
"getcfheaders" => new GetCompactFilterHeadersPayload(),
"getcfcheckpt" => new GetCompactFilterCheckPointPayload(),
"getheaders" => new GetHeadersPayload(),
"havewitness" => new HaveWitnessPayload(),
"mempool" => new MempoolPayload(),
"merkleblock" => new MerkleBlockPayload(),
"sendaddrv2" => new SendAddrV2Payload(),
"sendcmpct" => new SendCmpctPayload(),
"sendheaders" => new SendHeadersPayload(),
"utxos" => new UTxOutputPayload(),
"verack" => new VerAckPayload(),
"wtxidrelay" => new WTxIdRelayPayload(),
_ => new UnknownPayload(command)
};
}

public virtual ProtocolCapabilities GetProtocolCapabilities(uint protocolVersion)
{
return new ProtocolCapabilities()
Expand Down
2 changes: 1 addition & 1 deletion NBitcoin/Protocol/BitcoinSerializablePayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace NBitcoin.Protocol
{
public class BitcoinSerializablePayload<T> : Payload where T : IBitcoinSerializable, new()
public abstract class BitcoinSerializablePayload<T> : Payload where T : IBitcoinSerializable, new()
{
public BitcoinSerializablePayload()
{
Expand Down
13 changes: 3 additions & 10 deletions NBitcoin/Protocol/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ public bool IfPayloadIs<TPayload>(Action<TPayload> action) where TPayload : Payl
// We use this for big blocks, because the default array pool would allocate a new array. We do not need lot's of bucket such arrays are short lived.
readonly static Lazy<ArrayPool<byte>> BigArrayPool = new Lazy<ArrayPool<byte>>(() => ArrayPool<byte>.Create(0x02000000, 5), false);
ArrayPool<byte> GetArrayPool(int size) => size < 1_048_576 ? ArrayPool<byte>.Shared : BigArrayPool.Value;

public void ReadWrite(BitcoinStream stream)
{
if (Payload == null && stream.Serializing)
Expand Down Expand Up @@ -130,18 +129,12 @@ public void ReadWrite(BitcoinStream stream)
BitcoinStream payloadStream = new BitcoinStream(new MemoryStream(payloadBytes, 0, length, false), false);
payloadStream.CopyParameters(stream);

var payloadType = PayloadAttribute.GetCommandType(Command);
var unknown = payloadType == typeof(UnknownPayload);
if (unknown)
var payload = stream.ConsensusFactory.CreatePayload(Command);
if (payload is UnknownPayload)
Logs.NodeServer.LogWarning("Unknown command received {command}", Command);

IBitcoinSerializable payload = null;
if (!stream.ConsensusFactory.TryCreateNew(payloadType, out payload))
payload = (IBitcoinSerializable)Activator.CreateInstance(payloadType);
payload.ReadWrite(payloadStream);
if (unknown)
((UnknownPayload)payload)._Command = Command;
Payload = (Payload)payload;
Payload = payload;
}
finally
{
Expand Down
14 changes: 7 additions & 7 deletions NBitcoin/Protocol/Payload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

namespace NBitcoin.Protocol
{
public class Payload : IBitcoinSerializable
/// <summary>
/// A P2P Bitcoin payload
/// </summary>
public abstract class Payload : IBitcoinSerializable
{
public virtual string Command
public abstract string Command
{
get
{
return PayloadAttribute.GetCommandName(this.GetType());
}
get;
}

#region IBitcoinSerializable Members
Expand All @@ -34,7 +34,7 @@ public virtual void ReadWriteCore(BitcoinStream stream)

public override string ToString()
{
return this.GetType().Name;
return Command;
}
}
}
82 changes: 0 additions & 82 deletions NBitcoin/Protocol/PayloadAttribute.cs

This file was deleted.

166 changes: 84 additions & 82 deletions NBitcoin/Protocol/Payloads/AddrPayload.cs
Original file line number Diff line number Diff line change
@@ -1,82 +1,84 @@
#if !NOSOCKET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NBitcoin.Protocol
{
/// <summary>
/// An available peer address in the bitcoin network is announced (unsolicited or after a getaddr)
/// </summary>
[Payload("addr")]
public class AddrPayload : Payload, IBitcoinSerializable
{
NetworkAddress[] addr_list = new NetworkAddress[0];
public NetworkAddress[] Addresses
{
get
{
return addr_list;
}
}

public AddrPayload()
{

}
public AddrPayload(NetworkAddress address)
{
addr_list = new NetworkAddress[] { address };
}
public AddrPayload(NetworkAddress[] addresses)
{
addr_list = addresses.ToArray();
}

#region IBitcoinSerializable Members

public override void ReadWriteCore(BitcoinStream stream)
{
stream.ReadWrite(ref addr_list);
}

#endregion

public override string ToString()
{
return Addresses.Length + " address(es)";
}
}

/// <summary>
/// An available peer address in the bitcoin network is announced (unsolicited or after a getaddrv2)
/// </summary>
[Payload("addrv2")]
public class AddrV2Payload : AddrPayload
{
public AddrV2Payload()
: base()
{
}
public AddrV2Payload(NetworkAddress address)
: base(address)
{
}

public AddrV2Payload(NetworkAddress[] addresses)
: base(addresses)
{
}

public override void ReadWriteCore(BitcoinStream stream)
{
using (stream.ProtocolVersionScope(NetworkAddress.AddrV2Format))
{
base.ReadWriteCore(stream);
}
}
}
}
#endif
#if !NOSOCKET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NBitcoin.Protocol
{
/// <summary>
/// An available peer address in the bitcoin network is announced (unsolicited or after a getaddr)
/// </summary>

public class AddrPayload : Payload, IBitcoinSerializable
{
public override string Command => "addr";
NetworkAddress[] addr_list = new NetworkAddress[0];
public NetworkAddress[] Addresses
{
get
{
return addr_list;
}
}

public AddrPayload()
{

}
public AddrPayload(NetworkAddress address)
{
addr_list = new NetworkAddress[] { address };
}
public AddrPayload(NetworkAddress[] addresses)
{
addr_list = addresses.ToArray();
}

#region IBitcoinSerializable Members

public override void ReadWriteCore(BitcoinStream stream)
{
stream.ReadWrite(ref addr_list);
}

#endregion

public override string ToString()
{
return Addresses.Length + " address(es)";
}
}

/// <summary>
/// An available peer address in the bitcoin network is announced (unsolicited or after a getaddrv2)
/// </summary>

public class AddrV2Payload : AddrPayload
{
public override string Command => "addrv2";
public AddrV2Payload()
: base()
{
}
public AddrV2Payload(NetworkAddress address)
: base(address)
{
}

public AddrV2Payload(NetworkAddress[] addresses)
: base(addresses)
{
}

public override void ReadWriteCore(BitcoinStream stream)
{
using (stream.ProtocolVersionScope(NetworkAddress.AddrV2Format))
{
base.ReadWriteCore(stream);
}
}
}
}
#endif
3 changes: 2 additions & 1 deletion NBitcoin/Protocol/Payloads/BlockPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ namespace NBitcoin.Protocol
/// <summary>
/// A block received after being asked with a getdata message
/// </summary>
[Payload("block")]

public class BlockPayload : BitcoinSerializablePayload<Block>
{
public override string Command => "block";
public BlockPayload()
{

Expand Down
3 changes: 2 additions & 1 deletion NBitcoin/Protocol/Payloads/BlockTxnPayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

namespace NBitcoin.Protocol
{
[Payload("blocktxn")]

public class BlockTxnPayload : Payload
{
public override string Command => "blocktxn";

uint256 _BlockId;
public uint256 BlockId
Expand Down
Loading
Loading