Skip to content
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
43 changes: 32 additions & 11 deletions NBitcoin.Altcoins/Dogecoin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,19 @@ public AuxPow AuxPow
}
}
const int VERSION_AUXPOW = (1 << 8);
internal void ReadWriteHeader(BitcoinStream stream)
{
stream.ReadWrite(ref header);
if((header.Version & VERSION_AUXPOW) != 0)
{
stream.ReadWrite(ref auxPow);
}
}
public override void ReadWrite(BitcoinStream stream)
{
using (stream.ConsensusFactoryScope(GetConsensusFactory()))
{
stream.ReadWrite(ref header);
if((header.Version & VERSION_AUXPOW) != 0)
{
stream.ReadWrite(ref auxPow);
}
ReadWriteHeader(stream);
stream.ReadWrite(ref vtx);
}
}
Expand All @@ -238,23 +242,40 @@ public override ConsensusFactory GetConsensusFactory()
}
class DogecoinHeadersPayload : HeadersPayload
{
List<DogecoinBlock> blocks = new List<DogecoinBlock>();
class DogecoinHeaderWithTxCount : IBitcoinSerializable
{
internal DogecoinBlock Block = (DogecoinBlock)DogeConsensusFactory.Instance.CreateBlock();

public void ReadWrite(BitcoinStream stream)
{
using (stream.ConsensusFactoryScope(DogeConsensusFactory.Instance))
{
Block.ReadWriteHeader(stream);
if (stream.Serializing)
VarInt.StaticWrite(stream, 0);
else
VarInt.StaticRead(stream);
}
}
}

List<DogecoinHeaderWithTxCount> headers = new List<DogecoinHeaderWithTxCount>();

public override void ReadWriteCore(BitcoinStream stream)
{
if (stream.Serializing)
{
if (blocks.Count == Headers.Count && blocks.Select(b => b.Header).SequenceEqual(Headers))
stream.ReadWrite(ref blocks);
if (headers.Count == Headers.Count && headers.Select(h => h.Block.Header).SequenceEqual(Headers))
stream.ReadWrite(ref headers);
else
base.ReadWriteCore(stream);
return;
}

// Dogecoin serializes headers as blocks with empty transaction vectors.
stream.ReadWrite(ref blocks);
// Dogecoin Core parses each header and ignores its assumed-zero transaction count.
stream.ReadWrite(ref headers);
Headers.Clear();
Headers.AddRange(blocks.Select(b => b.Header));
Headers.AddRange(headers.Select(h => h.Block.Header));
}
}

Expand Down
21 changes: 21 additions & 0 deletions NBitcoin.Tests/AltcoinTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,27 @@ public void CanParseAuxPowDogeHeaders()
Assert.Equal(headersHex, Encoders.Hex.EncodeData(payload.ToBytes()));
}

[Fact]
public void DogeHeadersIgnoreTransactionCount()
{
var network = Dogecoin.Instance.Mainnet;
var block = Block.Parse(DogecoinAuxPowBlockHex, network);
block.Transactions.Clear();
var header = block.ToBytes();
header[header.Length - 1] = 1;
var headersBytes = new byte[] { 2 }
.Concat(header)
.Concat(block.ToBytes())
.ToArray();

var payload = network.Consensus.ConsensusFactory.CreatePayload("headers");
payload.ReadWrite(headersBytes, network);
var headers = Assert.IsAssignableFrom<HeadersPayload>(payload);

Assert.Equal(2, headers.Headers.Count);
Assert.All(headers.Headers, h => Assert.Equal(block.GetHash(), h.GetHash()));
}

[Fact]
public void NoCrashQuickTest()
{
Expand Down
Loading