Skip to content

Commit

Permalink
Provenheader not as inheritance class (#91)
Browse files Browse the repository at this point in the history
* Add block header store

* Fix consensus puller bug assertion

* Optimize chain work field as byte array insted of BigInteger

* Store proven header in a new field

* Fixing tests

* All code compiles

* Fix xds network

* Fix serializaton bug

* Fix xds and startup
  • Loading branch information
dangershony authored Apr 15, 2020
1 parent 2273fd4 commit cb3d5cc
Show file tree
Hide file tree
Showing 15 changed files with 126 additions and 96 deletions.
7 changes: 6 additions & 1 deletion src/Bitcoin/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{
"profiles": {
"Stratis.BitcoinD": {
"commandName": "Project"
"commandName": "Project",
"commandLineArgs": ""
},
"Stratis.BitcoinD Low memory": {
"commandName": "Project",
"commandLineArgs": "-maxblkmem=5 -dbcache=50"
},
"Stratis.BitcoinD Test": {
"commandName": "Project",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public void AddToPending_Then_Reorg_New_Items_Consecutive_Not_Tip_Then_Save()
// items 1-20 on main chain
foreach (ChainedHeader chainedHeader in chainedHeaders.Skip(1).Take(20))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(20, this.PendingBatch.Count);
Expand All @@ -289,7 +289,7 @@ public void AddToPending_Then_Reorg_New_Items_Consecutive_Not_Tip_Then_Save()
// 1-10 on main chain then items 10-15 on a fork
foreach (ChainedHeader chainedHeader in newChainedHeaders.Skip(10).Take(6))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(15, this.PendingBatch.Count);
Expand All @@ -313,7 +313,7 @@ public void AddToPending_Then_Reorg_New_Items_Consecutive_Is_Tip_Then_Save()
// items 1-20 on main chain
foreach (ChainedHeader chainedHeader in chainedHeaders.Skip(1).Take(21))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(20, this.PendingBatch.Count);
Expand All @@ -326,7 +326,7 @@ public void AddToPending_Then_Reorg_New_Items_Consecutive_Is_Tip_Then_Save()
// all items 1-20 are on main chain after a fork
foreach (ChainedHeader chainedHeader in newChainedHeaders.Skip(10).Take(11))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(20, this.PendingBatch.Count);
Expand All @@ -350,7 +350,7 @@ public void AddToPending_Then_Reorg_New_Items_Not_Consecutive_Is_Not_Tip_Then_Sa
// Items 1-15 pending
foreach (ChainedHeader chainedHeader in chainedHeaders.Skip(1).Take(15))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(15, this.PendingBatch.Count);
Expand All @@ -365,7 +365,7 @@ public void AddToPending_Then_Reorg_New_Items_Not_Consecutive_Is_Not_Tip_Then_Sa
// Add items 16-20
foreach (ChainedHeader chainedHeader in chainedHeaders.Skip(16).Take(5))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(5, this.PendingBatch.Count);
Expand All @@ -378,7 +378,7 @@ public void AddToPending_Then_Reorg_New_Items_Not_Consecutive_Is_Not_Tip_Then_Sa
// Add new fork items 10-13, items of the old fork 16-20 are still in the batch.
foreach (ChainedHeader chainedHeader in newChainedHeaders.Skip(10).Take(3))
{
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
}

Assert.Equal(3, this.PendingBatch.Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void ConstructProvenHeaderPayload_Consecutive_Headers()
var provenBlockHeadersToVerifyAgainst = new List<ProvenBlockHeader>();
for (int i = 5; i <= provenHeaderChain.Height; i++)
{
provenBlockHeadersToVerifyAgainst.Add((ProvenBlockHeader)provenHeaderChain.GetAncestor(i).Header);
provenBlockHeadersToVerifyAgainst.Add(((PosBlockHeader)provenHeaderChain.GetAncestor(i).Header).ProvenBlockHeader);
}

//Trigger the event handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void RunRule_ProvenHeadersNotActive_RuleIsSkipped()
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();

// Setup chained header and move it to the height below proven header activation height.
this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader, provenBlockHeader.GetHash(), null);
this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader.PosBlockHeader, provenBlockHeader.GetHash(), null);
this.checkpoints.Setup(c => c.GetLastCheckpointHeight()).Returns(100);

// When we run the validation rule, we should not hit any exceptions as rule will be skipped.
Expand Down Expand Up @@ -62,7 +62,7 @@ public void RunRule_ProvenHeadersActive_And_CoinstakeIsNull_EmptyCoinstakeErrorI
// Setup chained header and move it to the height higher than proven header activation height.
this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader, provenBlockHeader.GetHash(), null);
this.ruleContext.ValidationContext.ChainedHeaderToValidate.SetPrivatePropertyValue("Height", this.provenHeadersActivationHeight + 10);
this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header.SetPrivateVariableValue<Transaction>("coinstake", null);
(this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header as PosBlockHeader).ProvenBlockHeader.SetPrivateVariableValue<Transaction>("coinstake", null);

// When we run the validation rule, we should hit coinstake empty exception.
Action ruleValidation = () => this.consensusRules.RegisterRule<ProvenHeaderCoinstakeRule>().Run(this.ruleContext);
Expand Down Expand Up @@ -146,7 +146,7 @@ public void RunRule_ProvenHeadersActive_And_CoinstakeIsIncorrectlySetup_NonCoins
.Returns(res);

// Change coinstake outputs to make it invalid.
((ProvenBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).Coinstake.Outputs.RemoveAt(0);
((PosBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).ProvenBlockHeader.Coinstake.Outputs.RemoveAt(0);

Action ruleValidation = () => this.consensusRules.RegisterRule<ProvenHeaderCoinstakeRule>().Run(this.ruleContext);
ruleValidation.Should().Throw<ConsensusErrorException>()
Expand Down Expand Up @@ -174,7 +174,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidStakeTime_StakeTimeViolationE
.Returns(res);

// Change coinstake time to differ from header time but divisible by 16.
((ProvenBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).Time = 16;
((PosBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).Time = 16;

// When we run the validation rule, we should hit coinstake stake time violation error.
Action ruleValidation = () => this.consensusRules.RegisterRule<ProvenHeaderCoinstakeRule>().Run(this.ruleContext);
Expand All @@ -184,7 +184,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidStakeTime_StakeTimeViolationE

// Change coinstake time to be the same as header time but not divisible by 16.
this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header.Time = 50;
((ProvenBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).Time = 50;
((PosBlockHeader)this.ruleContext.ValidationContext.ChainedHeaderToValidate.Header).Time = 50;

// When we run the validation rule, we should hit coinstake stake time violation error.
ruleValidation.Should().Throw<ConsensusErrorException>()
Expand All @@ -204,7 +204,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidStakeDepth_StakeDepthErrorIsT
// Setup proven header with valid coinstake.
PosBlock posBlock = new PosBlockBuilder(this.network).Build();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand Down Expand Up @@ -247,7 +247,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeSignature_CoinstakeV
// Setup proven header with valid coinstake.
PosBlock posBlock = new PosBlockBuilder(this.network).Build();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand Down Expand Up @@ -296,7 +296,7 @@ public void RunRule_ProvenHeadersActive_And_NullPreviousStake_InvalidPreviousPro
// Setup proven header with valid coinstake.
PosBlock posBlock = new PosBlockBuilder(this.network).Build();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand Down Expand Up @@ -346,7 +346,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidStakeKernelHash_CoinstakeVeri
// Setup proven header with valid coinstake.
PosBlock posBlock = new PosBlockBuilder(this.network).Build();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand Down Expand Up @@ -402,7 +402,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidMerkleProof_BadMerkleProofErr
// Setup proven header with valid coinstake.
PosBlock posBlock = new PosBlockBuilder(this.network).Build();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand Down Expand Up @@ -463,7 +463,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeKernelSignature_BadB
PosBlock posBlock = new PosBlockBuilder(this.network, privateKey).Build();
posBlock.UpdateMerkleRoot();
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand All @@ -481,7 +481,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeKernelSignature_BadB
var unspentOutputs = new UnspentOutput(prevPosBlock.Transactions[1].Inputs[0].PrevOut,
new Coins(unspentOutputsHeight, new TxOut(new Money(100), privateKey.PubKey), false));

res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);
res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);

this.coinView
.Setup(m => m.FetchCoins(It.IsAny<OutPoint[]>()))
Expand Down Expand Up @@ -533,7 +533,7 @@ public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown(
posBlock.BlockSignature = new BlockSignature { Signature = signature.ToDER() };

ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
posTrx.Time = provenBlockHeader.Time;

Expand All @@ -550,7 +550,7 @@ public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown(
var res = new FetchCoinsResponse();
var unspentOutputs = new UnspentOutput(prevPosBlock.Transactions[1].Inputs[0].PrevOut,
new Coins(unspentOutputsHeight, new TxOut(new Money(100), privateKey.PubKey), false));

res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);

this.coinView
Expand All @@ -577,4 +577,4 @@ public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown(
ruleValidation.Should().NotThrow();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,4 @@ public void RunRule_OversizedSignature_And_ProvenHeadersNotActive_RuleIsSkipped(
ruleValidation.Should().NotThrow();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ protected override async Task OnMessageReceivedAsync(INetworkPeer peer, Incoming
switch (message.Message.Payload)
{
case ProvenHeadersPayload provenHeaders:
await this.ProcessHeadersAsync(peer, provenHeaders.Headers.Cast<BlockHeader>().ToList()).ConfigureAwait(false);
break;
{
await this.ProcessHeadersAsync(peer, provenHeaders.Headers.Select(s => s.PosBlockHeader).Cast<BlockHeader>().ToList()).ConfigureAwait(false);
break;
}

case GetProvenHeadersPayload getHeaders:
await this.ProcessGetHeadersAsync(peer, getHeaders).ConfigureAwait(false);
Expand Down Expand Up @@ -132,22 +134,6 @@ protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersP
return null;
}

for (int i = 0; i < headersPayload.Headers.Count; i++)
{
if (headersPayload.Headers[i] is ProvenBlockHeader phHeader)
{
BlockHeader newHeader = this.ChainIndexer.Network.Consensus.ConsensusFactory.CreateBlockHeader();
newHeader.Bits = phHeader.Bits;
newHeader.Time = phHeader.Time;
newHeader.Nonce = phHeader.Nonce;
newHeader.Version = phHeader.Version;
newHeader.HashMerkleRoot = phHeader.HashMerkleRoot;
newHeader.HashPrevBlock = phHeader.HashPrevBlock;

headersPayload.Headers[i] = newHeader;
}
}

return headersPayload;
}

Expand Down Expand Up @@ -182,12 +168,12 @@ protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersP
this.logger.LogTrace("(-)[NO_PH_AVAILABLE]");
break;
}
else if (provenBlockHeader.GetHash() != header.HashBlock)
else if (provenBlockHeader.PosBlockHeader.GetHash() != header.HashBlock)
{
// Proven header is in the store, but with a wrong hash.
// This can happen in case of reorgs, when the store has not yet been updated.
// Without this check, we may send headers that aren't consecutive because are built from different branches, and the other peer may ban us.
this.logger.LogDebug("Stored PH hash is wrong. Expected: {0}, Found: {1}", header.Header.GetHash(), provenBlockHeader.GetHash());
this.logger.LogDebug("Stored PH hash is wrong. Expected: {0}, Found: {1}", header.Header.GetHash(), provenBlockHeader.PosBlockHeader.GetHash());
this.logger.LogTrace("(-)[WRONG STORED PH]");
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected override void ProcessRule(PosRuleContext context, ChainedHeader chaine
ConsensusErrors.ProofOfWorkTooHigh.Throw();
}

if (!header.CheckProofOfWork())
if (!header.PosBlockHeader.CheckProofOfWork())
{
this.Logger.LogTrace("(-)[HIGH_HASH]");
ConsensusErrors.HighHash.Throw();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override ProvenBlockHeader CreateProvenBlockHeader()

public override ProvenBlockHeader CreateProvenBlockHeader(PosBlock block)
{
var provenBlockHeader = new XdsProvenBlockHeader(block);
var provenBlockHeader = new XdsProvenBlockHeader(block, (XdsBlockHeader)this.CreateBlockHeader());

// Serialize the size.
provenBlockHeader.ToBytes(this);
Expand Down
15 changes: 1 addition & 14 deletions src/Blockcore.Networks.Xds/Consensus/XdsProvenBlockHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,8 @@ public XdsProvenBlockHeader()
{
}

public XdsProvenBlockHeader(PosBlock block) : base(block)
public XdsProvenBlockHeader(PosBlock block, XdsBlockHeader xdsBlockHeader) : base(block, xdsBlockHeader)
{
}

public override uint256 GetPoWHash()
{
byte[] serialized;

using (var ms = new MemoryStream())
{
this.ReadWriteHashingStream(new BitcoinStream(ms, true));
serialized = ms.ToArray();
}

return Sha512T.GetHash(serialized);
}
}
}
Loading

0 comments on commit cb3d5cc

Please sign in to comment.