Skip to content

Commit cb3d5cc

Browse files
authored
Provenheader not as inheritance class (#91)
* 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
1 parent 2273fd4 commit cb3d5cc

15 files changed

Lines changed: 126 additions & 96 deletions

File tree

src/Bitcoin/Properties/launchSettings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
{
22
"profiles": {
33
"Stratis.BitcoinD": {
4-
"commandName": "Project"
4+
"commandName": "Project",
5+
"commandLineArgs": ""
6+
},
7+
"Stratis.BitcoinD Low memory": {
8+
"commandName": "Project",
9+
"commandLineArgs": "-maxblkmem=5 -dbcache=50"
510
},
611
"Stratis.BitcoinD Test": {
712
"commandName": "Project",

src/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderStoreTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ public void AddToPending_Then_Reorg_New_Items_Consecutive_Not_Tip_Then_Save()
276276
// items 1-20 on main chain
277277
foreach (ChainedHeader chainedHeader in chainedHeaders.Skip(1).Take(20))
278278
{
279-
this.provenBlockHeaderStore.AddToPendingBatch(chainedHeader.Header as ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
279+
this.provenBlockHeaderStore.AddToPendingBatch((chainedHeader.Header as PosBlockHeader).ProvenBlockHeader, new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height));
280280
}
281281

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

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

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

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

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

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

384384
Assert.Equal(3, this.PendingBatch.Count);

src/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenHeaderConsenusManagerBehaviorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void ConstructProvenHeaderPayload_Consecutive_Headers()
120120
var provenBlockHeadersToVerifyAgainst = new List<ProvenBlockHeader>();
121121
for (int i = 5; i <= provenHeaderChain.Height; i++)
122122
{
123-
provenBlockHeadersToVerifyAgainst.Add((ProvenBlockHeader)provenHeaderChain.GetAncestor(i).Header);
123+
provenBlockHeadersToVerifyAgainst.Add(((PosBlockHeader)provenHeaderChain.GetAncestor(i).Header).ProvenBlockHeader);
124124
}
125125

126126
//Trigger the event handler

src/Blockcore.Features.Consensus.Tests/Rules/ProvenHeaderRules/ProvenBlockHeaderCoinstakeRuleTest.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void RunRule_ProvenHeadersNotActive_RuleIsSkipped()
3333
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();
3434

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -463,7 +463,7 @@ public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeKernelSignature_BadB
463463
PosBlock posBlock = new PosBlockBuilder(this.network, privateKey).Build();
464464
posBlock.UpdateMerkleRoot();
465465
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
466-
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
466+
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
467467
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
468468
posTrx.Time = provenBlockHeader.Time;
469469

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

484-
res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);
484+
res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);
485485

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

535535
ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);
536-
provenBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
536+
provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
537537
if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
538538
posTrx.Time = provenBlockHeader.Time;
539539

@@ -550,7 +550,7 @@ public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown(
550550
var res = new FetchCoinsResponse();
551551
var unspentOutputs = new UnspentOutput(prevPosBlock.Transactions[1].Inputs[0].PrevOut,
552552
new Coins(unspentOutputsHeight, new TxOut(new Money(100), privateKey.PubKey), false));
553-
553+
554554
res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);
555555

556556
this.coinView
@@ -577,4 +577,4 @@ public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown(
577577
ruleValidation.Should().NotThrow();
578578
}
579579
}
580-
}
580+
}

src/Blockcore.Features.Consensus.Tests/Rules/ProvenHeaderRules/ProvenBlockHeaderSizeRuleTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,4 @@ public void RunRule_OversizedSignature_And_ProvenHeadersNotActive_RuleIsSkipped(
122122
ruleValidation.Should().NotThrow();
123123
}
124124
}
125-
}
125+
}

src/Blockcore.Features.Consensus/Behaviors/ProvenHeadersConsensusManagerBehavior.cs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ protected override async Task OnMessageReceivedAsync(INetworkPeer peer, Incoming
7777
switch (message.Message.Payload)
7878
{
7979
case ProvenHeadersPayload provenHeaders:
80-
await this.ProcessHeadersAsync(peer, provenHeaders.Headers.Cast<BlockHeader>().ToList()).ConfigureAwait(false);
81-
break;
80+
{
81+
await this.ProcessHeadersAsync(peer, provenHeaders.Headers.Select(s => s.PosBlockHeader).Cast<BlockHeader>().ToList()).ConfigureAwait(false);
82+
break;
83+
}
8284

8385
case GetProvenHeadersPayload getHeaders:
8486
await this.ProcessGetHeadersAsync(peer, getHeaders).ConfigureAwait(false);
@@ -132,22 +134,6 @@ protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersP
132134
return null;
133135
}
134136

135-
for (int i = 0; i < headersPayload.Headers.Count; i++)
136-
{
137-
if (headersPayload.Headers[i] is ProvenBlockHeader phHeader)
138-
{
139-
BlockHeader newHeader = this.ChainIndexer.Network.Consensus.ConsensusFactory.CreateBlockHeader();
140-
newHeader.Bits = phHeader.Bits;
141-
newHeader.Time = phHeader.Time;
142-
newHeader.Nonce = phHeader.Nonce;
143-
newHeader.Version = phHeader.Version;
144-
newHeader.HashMerkleRoot = phHeader.HashMerkleRoot;
145-
newHeader.HashPrevBlock = phHeader.HashPrevBlock;
146-
147-
headersPayload.Headers[i] = newHeader;
148-
}
149-
}
150-
151137
return headersPayload;
152138
}
153139

@@ -182,12 +168,12 @@ protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersP
182168
this.logger.LogTrace("(-)[NO_PH_AVAILABLE]");
183169
break;
184170
}
185-
else if (provenBlockHeader.GetHash() != header.HashBlock)
171+
else if (provenBlockHeader.PosBlockHeader.GetHash() != header.HashBlock)
186172
{
187173
// Proven header is in the store, but with a wrong hash.
188174
// This can happen in case of reorgs, when the store has not yet been updated.
189175
// Without this check, we may send headers that aren't consecutive because are built from different branches, and the other peer may ban us.
190-
this.logger.LogDebug("Stored PH hash is wrong. Expected: {0}, Found: {1}", header.Header.GetHash(), provenBlockHeader.GetHash());
176+
this.logger.LogDebug("Stored PH hash is wrong. Expected: {0}, Found: {1}", header.Header.GetHash(), provenBlockHeader.PosBlockHeader.GetHash());
191177
this.logger.LogTrace("(-)[WRONG STORED PH]");
192178
break;
193179
}

src/Blockcore.Features.Consensus/Rules/ProvenHeaderRules/ProvenHeaderCoinstakeRule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected override void ProcessRule(PosRuleContext context, ChainedHeader chaine
6363
ConsensusErrors.ProofOfWorkTooHigh.Throw();
6464
}
6565

66-
if (!header.CheckProofOfWork())
66+
if (!header.PosBlockHeader.CheckProofOfWork())
6767
{
6868
this.Logger.LogTrace("(-)[HIGH_HASH]");
6969
ConsensusErrors.HighHash.Throw();

src/Blockcore.Networks.Xds/Consensus/XdsConsensusFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public override ProvenBlockHeader CreateProvenBlockHeader()
2121

2222
public override ProvenBlockHeader CreateProvenBlockHeader(PosBlock block)
2323
{
24-
var provenBlockHeader = new XdsProvenBlockHeader(block);
24+
var provenBlockHeader = new XdsProvenBlockHeader(block, (XdsBlockHeader)this.CreateBlockHeader());
2525

2626
// Serialize the size.
2727
provenBlockHeader.ToBytes(this);

src/Blockcore.Networks.Xds/Consensus/XdsProvenBlockHeader.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,8 @@ public XdsProvenBlockHeader()
1010
{
1111
}
1212

13-
public XdsProvenBlockHeader(PosBlock block) : base(block)
13+
public XdsProvenBlockHeader(PosBlock block, XdsBlockHeader xdsBlockHeader) : base(block, xdsBlockHeader)
1414
{
1515
}
16-
17-
public override uint256 GetPoWHash()
18-
{
19-
byte[] serialized;
20-
21-
using (var ms = new MemoryStream())
22-
{
23-
this.ReadWriteHashingStream(new BitcoinStream(ms, true));
24-
serialized = ms.ToArray();
25-
}
26-
27-
return Sha512T.GetHash(serialized);
28-
}
2916
}
3017
}

0 commit comments

Comments
 (0)