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

Clean-up activation heights #1094

Open
wants to merge 11 commits into
base: release/1.4.0.0
Choose a base branch
from
14 changes: 10 additions & 4 deletions src/NBitcoin/BuriedDeploymentsArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ namespace NBitcoin
{
public class BuriedDeploymentsArray
{
private readonly int[] heights;
protected int[] heights;

public BuriedDeploymentsArray()
{
this.heights = new int[Enum.GetValues(typeof(BuriedDeployments)).Length];
this.heights = new int[0];
}

protected void EnsureIndex(int index)
{
if (index >= this.heights.Length)
Array.Resize(ref this.heights, index + 1);
}

public int this[BuriedDeployments index]
{
get => this.heights[(int)index];
set => this.heights[(int)index] = value;
get { EnsureIndex((int)index); return this.heights[(int)index]; }
set { EnsureIndex((int)index); this.heights[(int)index] = value; }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public TestPoANetwork(string networkName = "")
targetSpacingSeconds: 60,
votingEnabled: baseOptions.VotingEnabled,
autoKickIdleMembers: false,
contractSerializerV2ActivationHeight: 0,
federationMemberMaxIdleTimeSeconds: baseOptions.FederationMemberMaxIdleTimeSeconds
)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public async Task EnableAutoKickAsync()
targetSpacingSeconds: 60,
votingEnabled: true,
autoKickIdleMembers: false,
contractSerializerV2ActivationHeight: 0,
federationMemberMaxIdleTimeSeconds: oldOptions.FederationMemberMaxIdleTimeSeconds);

CoreNode node1 = builder.CreatePoANode(votingNetwork1, votingNetwork1.FederationKey1).Start();
Expand All @@ -54,6 +55,7 @@ public async Task EnableAutoKickAsync()
targetSpacingSeconds: 60,
votingEnabled: true,
autoKickIdleMembers: true,
contractSerializerV2ActivationHeight: 0,
federationMemberMaxIdleTimeSeconds: idleTimeSeconds);

// Restart node 1 to ensure that we have the new network consensus options which reflects
Expand Down
6 changes: 4 additions & 2 deletions src/Stratis.Bitcoin.Features.PoA.Tests/PoATestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,15 @@ public TestPoANetwork(List<PubKey> pubKeysOverride = null)
targetSpacingSeconds: 60,
votingEnabled: baseOptions.VotingEnabled,
autoKickIdleMembers: baseOptions.AutoKickIdleMembers,
contractSerializerV2ActivationHeight: 0,
federationMemberMaxIdleTimeSeconds: baseOptions.FederationMemberMaxIdleTimeSeconds
)
{
PollExpiryBlocks = 10,
Release1100ActivationHeight = 10
PollExpiryBlocks = 10
};

((PoABuriedDeploymentsArray)this.Consensus)[PoABuriedDeployments.Release1100] = 10;

this.Consensus.SetPrivatePropertyValue(nameof(this.Consensus.MaxReorgLength), (uint)5);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class PoAHeaderSignatureRule : FullValidationConsensusRule

private HashHeightPair lastCheckPoint;

private PoAConsensusOptions poAConsensusOptions;
private IConsensus consensus;

/// <inheritdoc />
public override void Initialize()
Expand All @@ -37,7 +37,7 @@ public override void Initialize()
this.slotsManager = engine.SlotsManager;
this.federationHistory = engine.FederationHistory;
this.validator = engine.PoaHeaderValidator;
this.poAConsensusOptions = engine.Network.Consensus.Options as PoAConsensusOptions;
this.consensus = engine.Network.Consensus;

KeyValuePair<int, CheckpointInfo> lastCheckPoint = engine.Network.Checkpoints.LastOrDefault();
this.lastCheckPoint = (lastCheckPoint.Value != null) ? new HashHeightPair(lastCheckPoint.Value.Hash, lastCheckPoint.Key) : null;
Expand Down Expand Up @@ -75,7 +75,7 @@ public override Task RunAsync(RuleContext context)
PoAConsensusErrors.InvalidHeaderSignature.Throw();
}

if (chainedHeader.Height >= this.poAConsensusOptions.GetMiningTimestampV2ActivationStrictHeight)
if (chainedHeader.Height >= this.consensus.PoABuriedDeployments(PoABuriedDeployments.GetMiningTimestampV2Strict))
{
uint expectedSlot = this.slotsManager.GetMiningTimestamp(chainedHeader.Previous, chainedHeader.Header.Time, pubKey);

Expand Down
2 changes: 1 addition & 1 deletion src/Stratis.Bitcoin.Features.PoA/FederationHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private IFederationMember[] GetFederationMembersForBlocks(ChainedHeader lastHead
IFederationMember[] miners = new IFederationMember[headers.Length];

// Reading chainedHeader's "Header" does not play well with asynchronocity so we will load the block times here.
int votingManagerV2ActivationHeight = (this.network.Consensus.Options as PoAConsensusOptions).VotingManagerV2ActivationHeight;
int votingManagerV2ActivationHeight = this.network.Consensus.PoABuriedDeployments(PoABuriedDeployments.VotingManagerV2);

int startHeight = lastHeader.Height + 1 - count;

Expand Down
113 changes: 67 additions & 46 deletions src/Stratis.Bitcoin.Features.PoA/PoAConsensusOptions.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NBitcoin;

namespace Stratis.Bitcoin.Features.PoA
{
public class PoAConsensusOptions : ConsensusOptions
public enum PoABuriedDeployments
{
/// <summary>Public keys and other federation members related information at the start of the chain.</summary>
/// <remarks>
/// Do not use this list anywhere except for at the initialization of the chain.
/// Actual collection of the federation members can be changed with time.
/// Use <see cref="IFederationManager.GetFederationMembers"/> as a source of
/// up to date federation keys.
/// </remarks>
public List<IFederationMember> GenesisFederationMembers { get; protected set; }

/// <summary>
/// The number of elapsed seconds required between mined block.
/// </summary>
public uint TargetSpacingSeconds { get; protected set; }

/// <summary>Adds capability of voting for adding\kicking federation members and other things.</summary>
public bool VotingEnabled { get; protected set; }

/// <summary>Makes federation members kick idle members.</summary>
/// <remarks>Requires voting to be enabled to be set <c>true</c>.</remarks>
public bool AutoKickIdleMembers { get; set; }

/// <summary>Time that federation member has to be idle to be kicked by others in case <see cref="AutoKickIdleMembers"/> is enabled.</summary>
public uint FederationMemberMaxIdleTimeSeconds { get; protected set; }

/// <summary>
/// This currently only applies to Cirrus Main Net.
/// This is the height on the main chain at which the dynamic fees paid to the multsig for interop conversion requests will activate.
/// </summary>
public uint? FederationMemberActivationTime { get; set; }
InterFluxV2MainChain,

/// <summary>
/// The height at which a federation members will be resolved via the <see cref="FederationHistory"/> class.
Expand All @@ -46,43 +23,86 @@ public class PoAConsensusOptions : ConsensusOptions
/// method which resolves the pubkey from the signature directly.
/// </para>
/// </summary>
public int VotingManagerV2ActivationHeight { get; set; }
VotingManagerV2,

/// <summary>
/// This is the height on the main chain at which the dynamic fees paid to the multsig for interop conversion requests will activate.
/// Defines when V2 of the contract serializer will be used.
/// I.e if tip <= ContractSerializerV2ActivationHeight, V1 will be used.
/// </summary>
ContractSerializerV2,

/// <summary>
/// Logic related to release 1.1.0.0 will activate at this height, this includes Poll Expiry and the Join Federation Voting Request consensus rule.
/// </summary>
public int InterFluxV2MainChainActivationHeight { get; set; }
Release1100,

/// <summary>
/// The height at which inituitive mining slots become active.
/// Legacy mining slots are determined by mining_slot = block_height % number_of_federation_members.
/// Once the specified height is reached there should no longer be a shift in mining slots when new federation members are added/removed.
/// </summary>
GetMiningTimestampV2,

/// <summary>
/// The height at which inituitive mining slots are enfored without any lenience.
/// Currently errors are sometimes suppressed if a federation change occurred.
/// </summary>
GetMiningTimestampV2Strict,

/// <summary>
/// The height at which Release 1.3.0.0 became BIP activated.
/// </summary>
public int Release1300ActivationHeight { get; set; }
Release1300,

/// <summary>
/// The height at which Release 1.3.2.0 became BIP activated.
/// </summary>
Release1320,

/// <summary>
/// The height at which Release 1.3.2.4 became BIP activated.
/// </summary>
Release1324,

/// <summary>
/// The height at which Release 1.4.0.0 became active.
/// <para>
/// This was primarily used for activating ScriptPubkey sorting for paying multisig recipients.
/// </para>
/// </summary>
public int Release1400ActivationHeight { get; set; }
Release1400
}

/// <summary>
/// The height at which inituitive mining slots become active.
/// Legacy mining slots are determined by mining_slot = block_height % number_of_federation_members.
/// Once the specified height is reached there should no longer be a shift in mining slots when new federation members are added/removed.
/// </summary>
public int GetMiningTimestampV2ActivationHeight { get; set; }
public class PoAConsensusOptions : ConsensusOptions
{
/// <summary>Public keys and other federation members related information at the start of the chain.</summary>
/// <remarks>
/// Do not use this list anywhere except for at the initialization of the chain.
/// Actual collection of the federation members can be changed with time.
/// Use <see cref="IFederationManager.GetFederationMembers"/> as a source of
/// up to date federation keys.
/// </remarks>
public List<IFederationMember> GenesisFederationMembers { get; protected set; }

/// <summary>
/// The height at which inituitive mining slots are enfored without any lenience.
/// Currently errors are sometimes suppressed if a federation change occurred.
/// The number of elapsed seconds required between mined block.
/// </summary>
public int GetMiningTimestampV2ActivationStrictHeight { get; set; }
public uint TargetSpacingSeconds { get; protected set; }

/// <summary>Adds capability of voting for adding\kicking federation members and other things.</summary>
public bool VotingEnabled { get; protected set; }

/// <summary>Makes federation members kick idle members.</summary>
/// <remarks>Requires voting to be enabled to be set <c>true</c>.</remarks>
public bool AutoKickIdleMembers { get; set; }

/// <summary>Time that federation member has to be idle to be kicked by others in case <see cref="AutoKickIdleMembers"/> is enabled.</summary>
public uint FederationMemberMaxIdleTimeSeconds { get; protected set; }

/// <summary>
/// Logic related to release 1.1.0.0 will activate at this height, this includes Poll Expiry and the Join Federation Voting Request consensus rule.
/// This currently only applies to Cirrus Main Net.
/// </summary>
public int Release1100ActivationHeight { get; set; }
public uint? FederationMemberActivationTime { get; set; }

/// <summary>
/// Polls are expired once the tip reaches a block this far beyond the poll start block.
Expand All @@ -91,8 +111,7 @@ public class PoAConsensusOptions : ConsensusOptions
public int PollExpiryBlocks { get; set; }

/// <summary>
/// Defines when V2 of the contract serializer will be used.
/// I.e if tip <= ContractSerializerV2ActivationHeight, V1 will be used.
/// Leaving this for now for use by Stratis.SmartContracts.CLR.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment still applicable? It seems that ContractPrimitiveSerializer is using the new approach

Copy link
Contributor Author

@quantumagi quantumagi Nov 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to reduce the chances of possible version incompatibilities where projects may still be using the older Stratis.SmartContracs.CLR NuGets such as Stratis.SmartContracts within say test projects that use network classes that don't have the field available. Can't remember the exact circumstance that caused issues for me but I concluded this would do more good than harm and can easily be removed in the future.

/// </summary>
public int ContractSerializerV2ActivationHeight { get; set; }

Expand All @@ -107,6 +126,7 @@ public class PoAConsensusOptions : ConsensusOptions
/// <param name="votingEnabled">See <see cref="VotingEnabled"/>.</param>
/// <param name="autoKickIdleMembers">See <see cref="AutoKickIdleMembers"/>.</param>
/// <param name="federationMemberMaxIdleTimeSeconds">See <see cref="FederationMemberMaxIdleTimeSeconds"/>.</param>
/// <param name="contractSerializerV2ActivationHeight">See <see cref="ContractSerializerV2ActivationHeight"/>.</param>
public PoAConsensusOptions(
uint maxBlockBaseSize,
int maxStandardVersion,
Expand All @@ -117,6 +137,7 @@ public PoAConsensusOptions(
uint targetSpacingSeconds,
bool votingEnabled,
bool autoKickIdleMembers,
int contractSerializerV2ActivationHeight,
uint federationMemberMaxIdleTimeSeconds = 60 * 60 * 24 * 7)
: base(maxBlockBaseSize, maxStandardVersion, maxStandardTxWeight, maxBlockSigopsCost, maxStandardTxSigopsCost, witnessScaleFactor: 1)
{
Expand All @@ -125,7 +146,7 @@ public PoAConsensusOptions(
this.VotingEnabled = votingEnabled;
this.AutoKickIdleMembers = autoKickIdleMembers;
this.FederationMemberMaxIdleTimeSeconds = federationMemberMaxIdleTimeSeconds;
this.InterFluxV2MainChainActivationHeight = 0;
this.ContractSerializerV2ActivationHeight = contractSerializerV2ActivationHeight;

if (this.AutoKickIdleMembers && !this.VotingEnabled)
throw new ArgumentException("Voting should be enabled for automatic kicking to work.");
Expand Down
27 changes: 19 additions & 8 deletions src/Stratis.Bitcoin.Features.PoA/PoANetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@

namespace Stratis.Bitcoin.Features.PoA
{
public class PoABuriedDeploymentsArray : BuriedDeploymentsArray
{
public int this[PoABuriedDeployments index]
{
get { EnsureIndex((int)index); return this.heights[(int)index]; }
set { EnsureIndex((int)index); this.heights[(int)index] = value; }
}
}

public static class ConsensusExt
{
public static int PoABuriedDeployments(this IConsensus consensus, PoABuriedDeployments index)
{
return ((PoABuriedDeploymentsArray)consensus.BuriedDeployments)[index];
}
}

/// <summary>
/// Example network for PoA consensus.
/// </summary>
Expand Down Expand Up @@ -106,19 +123,13 @@ public PoANetwork()
genesisFederationMembers: genesisFederationMembers,
targetSpacingSeconds: 16,
votingEnabled: true,
contractSerializerV2ActivationHeight: 0,
autoKickIdleMembers: true
)
{
PollExpiryBlocks = 450
};

var buriedDeployments = new BuriedDeploymentsArray
{
[BuriedDeployments.BIP34] = 0,
[BuriedDeployments.BIP65] = 0,
[BuriedDeployments.BIP66] = 0
};

var bip9Deployments = new NoBIP9Deployments();

this.Consensus = new NBitcoin.Consensus(
Expand All @@ -130,7 +141,7 @@ public PoANetwork()
majorityEnforceBlockUpgrade: 750,
majorityRejectBlockOutdated: 950,
majorityWindow: 1000,
buriedDeployments: buriedDeployments,
buriedDeployments: new PoABuriedDeploymentsArray(),
bip9Deployments: bip9Deployments,
bip34Hash: new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"),
minerConfirmationWindow: 2016, // nPowTargetTimespan / nPowTargetSpacing
Expand Down
5 changes: 4 additions & 1 deletion src/Stratis.Bitcoin.Features.PoA/SlotsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public interface ISlotsManager

public class SlotsManager : ISlotsManager
{
private readonly IConsensus consensus;

private readonly PoAConsensusOptions consensusOptions;

private readonly IFederationManager federationManager;
Expand All @@ -50,6 +52,7 @@ public SlotsManager(Network network, IFederationManager federationManager, IFede
this.federationManager = Guard.NotNull(federationManager, nameof(federationManager));
this.federationHistory = federationHistory;
this.chainIndexer = chainIndexer;
this.consensus = (network as PoANetwork).Consensus;
this.consensusOptions = (network as PoANetwork).ConsensusOptions;
}

Expand All @@ -73,7 +76,7 @@ The fact that the federation can change at any time adds extra complexity to thi
The miner that mined the last block may no longer exist when the next block is about to be mined. As such
we may need to look a bit further back to find a "reference miner" that still occurs in the latest federation.
*/
if (tip.Height < this.consensusOptions.GetMiningTimestampV2ActivationHeight)
if (tip.Height < this.consensus.PoABuriedDeployments(PoABuriedDeployments.GetMiningTimestampV2))
return GetMiningTimestampLegacy(tip, currentTime, currentMiner);

List<IFederationMember> federationMembers = this.federationHistory.GetFederationForBlock(tip, 1);
Expand Down
2 changes: 1 addition & 1 deletion src/Stratis.Bitcoin.Features.PoA/Voting/PollsRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ public List<Poll> GetAllPolls(DBreeze.Transactions.Transaction transaction)

private static int GetPollExpiryHeight(Poll poll, PoANetwork network)
{
return Math.Max(poll.PollStartBlockData.Height + network.ConsensusOptions.PollExpiryBlocks, network.ConsensusOptions.Release1100ActivationHeight);
return Math.Max(poll.PollStartBlockData.Height + network.ConsensusOptions.PollExpiryBlocks, network.Consensus.PoABuriedDeployments(PoABuriedDeployments.Release1100));
}

public static int GetPollExpiryOrExecutionHeight(Poll poll, PoANetwork network)
Expand Down
Loading