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

[WIP] Compact Filter protocol messages #548

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
108 changes: 108 additions & 0 deletions NBitcoin/Protocol/Payloads/CompactFilterCheckPointPayload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;

namespace NBitcoin.Protocol
{

[Payload("cfcheckpt")]
public class CompactFilterCheckPointPayload : Payload, IBitcoinSerializable
{
private byte _FilterType = 0;
private uint256 _StopHash = new uint256();
private uint256[] _FilterHeaders = { };
private VarInt _FilterHeadersLength = new VarInt(0);
public CompactFilterCheckPointPayload()
{

}

public CompactFilterCheckPointPayload(FilterType filterType, uint256 stopHash, uint filtersHeaderLength, byte[] filterHeaders)
{
if (filterType != FilterType.Basic /*&& filterType != FilterType.Extended*/) //Extended filters removed
throw new ArgumentException(nameof(filterType));
if (stopHash == null)
throw new ArgumentException(nameof(stopHash));
if (filterHeaders == null)
throw new ArgumentException(nameof(filterHeaders));

FilterType = filterType;
_StopHash = stopHash;
_FilterHeaders = GetHashes(filterHeaders);
}

private uint256[] GetHashes(byte[] filterHeaders)
{
int bytesToTake = 32;
int bytesTaken = 0;
List<uint256> temp = new List<uint256>();

List<BlockHeader> blockHeaders = new List<BlockHeader>();

for (; bytesTaken < filterHeaders.Length; bytesTaken += bytesToTake)
{
var subArray = filterHeaders.SafeSubarray(bytesTaken, bytesToTake);

temp.Add(new uint256(subArray));
}

return temp.ToArray();
}

public FilterType FilterType
{
get => (FilterType)_FilterType;
internal set => _FilterType = (byte)value;
}
public uint256 StopHash { get => _StopHash; set => _StopHash = value; }
public uint256[] FilterHeaders { get => _FilterHeaders; set => _FilterHeaders = value; }
public VarInt FilterHeadersLength { get => _FilterHeadersLength; set => _FilterHeadersLength = value; }

public new void ReadWrite(BitcoinStream stream)
{
var length = stream.Inner.Length;

stream.ReadWrite(ref _FilterType);
stream.ReadWrite(ref _StopHash);
stream.ReadWrite(ref _FilterHeadersLength);

//when serializing(Writing) we have to fill the tempfilterHeaders
if (stream.Serializing)
{
//turn the uint256[] into a byte array to write back into the bitcoin stream
List<byte> _tempfilterHeaders = new List<byte>();
byte[] _tempFilterHeaderBytes = new byte[_FilterHeadersLength.ToLong() * 32]; //Init byte array to hold list after conversion

foreach (var hash in _FilterHeaders)
{
foreach (var bytee in hash.ToBytes())
{
_tempfilterHeaders.Add(bytee);

}
}
//Write bytes
_tempFilterHeaderBytes = _tempfilterHeaders.ToArray();
stream.ReadWrite(ref _tempFilterHeaderBytes);
}


if (!stream.Serializing)
{
//instantiate a byte[] to hold the incoming hashes
var _tempfilterHeaders = new byte[_FilterHeadersLength.ToLong() * 32];

//Write filters to temp variable
stream.ReadWrite(ref _tempfilterHeaders);

//Convert the byte[] into "readable" uint256 hashes
_FilterHeaders = GetHashes(_tempfilterHeaders);
}
}


public override string ToString()
{
return $"cfcheckpt - filter type: {this._FilterType}| Stop Hash {this.StopHash}| # of checkpoints: {this._FilterHeadersLength.ToLong()}";
}
}
}
112 changes: 112 additions & 0 deletions NBitcoin/Protocol/Payloads/CompactFilterHeadersPayload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;

namespace NBitcoin.Protocol
{
[Payload("cfheaders")]
public class CompactFilterHeadersPayload: Payload, IBitcoinSerializable
{
private byte _FilterType = 0;
private uint256 _StopHash = new uint256();
private uint256 _PreviousFilterHeader = new uint256();
private VarInt _FilterHashesLength = new VarInt(0);
private uint256[] _FilterHashes = { };

public CompactFilterHeadersPayload(FilterType filterType, uint256 stopHash, uint256 previousFilterHeader, byte[] filterHashes)
{
if (filterType != FilterType.Basic /*&& filterType != FilterType.Extended*/) //Extended filters removed
throw new ArgumentException($"'{filterType}' is not a valid value. Try with Basic.", nameof(filterType));
if (stopHash == null)
throw new ArgumentException(nameof(stopHash));
if (previousFilterHeader == null)
throw new ArgumentException(nameof(previousFilterHeader));
if (filterHashes == null)
throw new ArgumentException(nameof(filterHashes));


FilterType = filterType;
_StopHash = stopHash;
_PreviousFilterHeader = previousFilterHeader;
_FilterHashes = GetHashes(filterHashes);
}

public CompactFilterHeadersPayload() { }

public FilterType FilterType
{
get => (FilterType)_FilterType;
internal set => _FilterType = (byte)value;
}

public new void ReadWrite(BitcoinStream stream)
{
stream.ReadWrite(ref _FilterType);
stream.ReadWrite(ref _StopHash);
stream.ReadWrite(ref _PreviousFilterHeader);
stream.ReadWrite(ref _FilterHashesLength);
//var _tempfilterHeaders = new byte[_filterHashesLength.ToLong() * 32];

if (stream.Serializing)
{
//turn the uint256[] into a byte array to write back into the bitcoin stream
List<byte> _tempfilterHeaders = new List<byte>();
byte[] _tempFilterHeaderBytes = new byte[_FilterHashesLength.ToLong() * 32]; //Init byte array to hold list after conversion

foreach (var hash in _FilterHashes)
{
foreach (var bytee in hash.ToBytes())
{
_tempfilterHeaders.Add(bytee);

}
}
//Write bytes
_tempFilterHeaderBytes = _tempfilterHeaders.ToArray();
stream.ReadWrite(ref _tempFilterHeaderBytes);
}


if (!stream.Serializing)
{
//instantiate a byte[] to hold the incoming hashes
var _tempfilterHeaders = new byte[_FilterHashesLength.ToLong() * 32];

//Write filters to temp variable
stream.ReadWrite(ref _tempfilterHeaders);

//Convert the byte[] into "readable" uint256 hashes
_FilterHashes = GetHashes(_tempfilterHeaders);
}
}

private uint256[] GetHashes(byte[] filterHeaders)
{
int bytesToTake = 32;
int bytesTaken = 0;
List<uint256> temp = new List<uint256>();

List<BlockHeader> blockHeaders = new List<BlockHeader>();

for (; bytesTaken < filterHeaders.Length; bytesTaken += bytesToTake)
{
var subArray = filterHeaders.SafeSubarray(bytesTaken, bytesToTake);

temp.Add(new uint256(subArray));
}

return temp.ToArray();
}


public uint256 StopHash => _StopHash;
public uint256 PreviousFilterHeader => _PreviousFilterHeader;
public uint256[] FilterHashes => _FilterHashes;



public override string ToString()
{
return $"Cheaders type: {this.FilterType}| # of headers: {this._FilterHashesLength.ToLong()}| Stop Hash: {this.StopHash}| Previous Filter Header Hash: {this.PreviousFilterHeader}";
}
}
}
83 changes: 83 additions & 0 deletions NBitcoin/Protocol/Payloads/CompactFilterPayload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;

namespace NBitcoin.Protocol
{

/// <summary>
/// Represents the p2p message payload used for sharing a block's compact filter.
/// </summary>
[Payload("cfilter")]
public class CompactFilterPayload : Payload
{
private byte _FilterType = 0;
private byte[] _FilterBytes;
private VarInt _NumFilterBytes = new VarInt(0);
private uint256 _BlockHash = new uint256();

/// <summary>
/// Gets the Filter type for which headers are requested
/// </summary>
public FilterType FilterType
{
get => (FilterType)_FilterType;
internal set => _FilterType = (byte)value;
}
/// <summary>
/// Gets the serialized compact filter for this block
/// </summary>
public byte[] FilterBytes => _FilterBytes;


/// <summary>
/// Gets block hash of the Bitcoin block for which the filter is being returned
/// </summary>
public uint256 BlockHash => _BlockHash;
public CompactFilterPayload(FilterType filterType, uint256 blockhash, byte[] filterBytes)
{
if (filterType != FilterType.Basic /*&& filterType != FilterType.Extended*/) //Extended filters removed
throw new ArgumentException($"'{filterType}' is not a valid value. Try with Basic.", nameof(filterType));
if (blockhash == null)
throw new ArgumentNullException(nameof(blockhash));
if (filterBytes == null)
throw new ArgumentNullException(nameof(filterBytes));


FilterType = filterType;
_BlockHash = blockhash;
_FilterBytes = filterBytes;
}

public CompactFilterPayload()
{
}

#region IBitcoinSerializable Members

public new void ReadWrite(BitcoinStream stream)
{
stream.ReadWrite(ref _FilterType);
stream.ReadWrite(ref _BlockHash);
stream.ReadWrite(ref _FilterBytes);
}

#endregion

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

stream.ReadWrite(ref _BlockHash);

stream.ReadWrite(ref _NumFilterBytes);

_FilterBytes = new byte[_NumFilterBytes.ToLong()];

stream.ReadWrite(ref _FilterBytes);
}

public override string ToString()
{
return $"Cfilter type: {this.FilterType}| Block hash: {this.BlockHash}| cfilter bytes omitted.";
}
}
}
Loading