Skip to content

Commit 676c51c

Browse files
authored
Merge pull request #978 from quantumagi/straxactivation
Access Cirrus cross-chain feature activations from the main chain
2 parents d9114b3 + d38dde0 commit 676c51c

File tree

9 files changed

+161
-46
lines changed

9 files changed

+161
-46
lines changed

src/Stratis.Bitcoin.Features.Consensus/ConsensusController.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,13 @@ public IActionResult LockedInDeployments()
109109

110110
List<ThresholdStateModel> metrics = ruleEngine.NodeDeployments.BIP9.GetThresholdStateMetrics(this.ChainState.ConsensusTip.Previous, thresholdStates, activationHeights);
111111

112-
return this.Json(metrics.Select(m => new ThresholdActivationModel() { activationHeight = m.SinceHeight, DeploymentIndex = m.DeploymentIndex, DeploymentName = m.DeploymentName, Votes = m.Votes }).ToArray());
112+
return this.Json(metrics.Select(m => new ThresholdActivationModel() {
113+
ActivationHeight = m.SinceHeight,
114+
DeploymentIndex = m.DeploymentIndex,
115+
DeploymentName = m.DeploymentName,
116+
Votes = m.Votes,
117+
LockedInHeight = m.SinceHeight - ruleEngine.Network.Consensus.MinerConfirmationWindow,
118+
LockedInTimestamp = this.ChainIndexer[m.SinceHeight - ruleEngine.Network.Consensus.MinerConfirmationWindow].Header.Time}).ToArray());
113119
}
114120
catch (Exception e)
115121
{

src/Stratis.Bitcoin/Base/Deployments/Models/ThresholdActivationModel.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,24 @@ public class ThresholdActivationModel
2323
/// Activation height.
2424
/// </summary>
2525
[JsonProperty(PropertyName = "activationHeight")]
26-
public int activationHeight { get; set; }
26+
public int ActivationHeight { get; set; }
2727

2828
/// <summary>
2929
/// Number of blocks with flags set that led to the deployment being locked in.
3030
/// </summary>
3131
[JsonProperty(PropertyName = "votes")]
3232
public int Votes { get; set; }
33+
34+
/// <summary>
35+
/// The height at which the deployment was locked-in.
36+
/// </summary>
37+
[JsonProperty(PropertyName = "lockedInHeight")]
38+
public int? LockedInHeight { get; set; }
39+
40+
/// <summary>
41+
/// The timestamp of the blocked at the "lockedInHeight".
42+
/// </summary>
43+
[JsonProperty(PropertyName = "lockedInTimestamp")]
44+
public long? LockedInTimestamp { get; set; }
3345
}
3446
}

src/Stratis.Bitcoin/Base/Deployments/ThresholdConditionCache.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ public List<ThresholdStateModel> GetThresholdStateMetrics(ChainedHeader indexPre
103103
// Choose the last header that's within the window where voting led to locked-in state.
104104
sinceHeight = activationHeights[deploymentIndex];
105105
indexPrev = referenceHeader.GetAncestor(sinceHeight - period - 1);
106+
if (indexPrev == null)
107+
continue;
106108
}
107109
else
108110
{

src/Stratis.Features.FederatedPeg.Tests/ControllersTests/FederationGatewayControllerTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public FederationGatewayControllerTests()
7474

7575
private FederationGatewayController CreateController(IFederatedPegSettings federatedPegSettings)
7676
{
77-
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), federatedPegSettings);
77+
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), federatedPegSettings, null, null);
7878

7979
var controller = new FederationGatewayController(
8080
Substitute.For<IAsyncProvider>(),
@@ -210,7 +210,7 @@ public void Call_Sidechain_Gateway_Get_Info()
210210

211211
var federatedPegSettings = new FederatedPegSettings(nodeSettings, new CounterChainNetworkWrapper(KnownNetworks.StraxRegTest));
212212

213-
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), federatedPegSettings);
213+
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), federatedPegSettings, null, null);
214214

215215
var controller = new FederationGatewayController(
216216
Substitute.For<IAsyncProvider>(),
@@ -304,7 +304,7 @@ public void Call_Mainchain_Gateway_Get_Info()
304304
this.federationWalletManager.IsFederationWalletActive().Returns(true);
305305

306306
var settings = new FederatedPegSettings(nodeSettings, new CounterChainNetworkWrapper(KnownNetworks.StraxRegTest));
307-
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), settings);
307+
var retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), settings, null, null);
308308

309309
var controller = new FederationGatewayController(
310310
Substitute.For<IAsyncProvider>(),

src/Stratis.Features.FederatedPeg.Tests/DepositExtractorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public DepositExtractorTests()
5555
this.depositExtractor = new DepositExtractor(this.conversionRequestRepository, this.federationSettings, this.network, this.opReturnDataReader);
5656
this.transactionBuilder = new TestTransactionBuilder();
5757

58-
this.retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), this.federationSettings);
58+
this.retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), this.federationSettings, null, null);
5959
}
6060

6161
// Normal Deposits

src/Stratis.Features.FederatedPeg.Tests/MaturedBlocksProviderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public MaturedBlocksProviderTests()
8080
return this.blocks.SkipWhile(x => x.ChainedHeader.Height <= chainedHeader.Height).Where(x => x.ChainedHeader.Height <= this.consensusManager.Tip.Height).ToArray();
8181
});
8282

83-
this.retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), this.federatedPegSettings);
83+
this.retrievalTypeConfirmations = new RetrievalTypeConfirmations(this.network, new NodeDeployments(this.network, new ChainIndexer(this.network)), this.federatedPegSettings, null, null);
8484
}
8585

8686
[Fact]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using System.Net.Http;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Stratis.Bitcoin.Base.Deployments.Models;
6+
using Stratis.Bitcoin.Controllers;
7+
using Stratis.Features.PoA.Collateral.CounterChain;
8+
9+
namespace Stratis.Features.FederatedPeg.Controllers
10+
{
11+
public class CounterChainConsensusClient : RestApiClientBase
12+
{
13+
/// <summary>
14+
/// Accesses the consensus controller on the counter-chain.
15+
/// <para>
16+
/// In a production/live scenario the sidechain and mainnet federation nodes should run on the same machine.
17+
/// </para>
18+
/// </summary>
19+
/// <param name="counterChainSettings">The counter-chain settings.</param>
20+
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> implementation.</param>
21+
public CounterChainConsensusClient(ICounterChainSettings counterChainSettings, IHttpClientFactory httpClientFactory)
22+
: base(httpClientFactory, counterChainSettings.CounterChainApiPort, "Consensus", $"http://{counterChainSettings.CounterChainApiHost}")
23+
{
24+
}
25+
26+
public Task<List<ThresholdActivationModel>> GetLockedInDeployments(CancellationToken cancellation = default)
27+
{
28+
return this.SendGetRequestAsync<List<ThresholdActivationModel>>("lockedindeployments", null, cancellation);
29+
}
30+
}
31+
}

src/Stratis.Features.FederatedPeg/SourceChain/RetrievalTypeConfirmations.cs

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using NBitcoin;
44
using Stratis.Bitcoin.Base.Deployments;
55
using Stratis.Features.FederatedPeg.Interfaces;
6+
using Stratis.Features.FederatedPeg.TargetChain;
7+
using Stratis.Features.PoA.Collateral.CounterChain;
68

79
namespace Stratis.Features.FederatedPeg.SourceChain
810
{
@@ -28,69 +30,53 @@ public class RetrievalTypeConfirmations : IRetrievalTypeConfirmations
2830
private const int MediumConfirmations = 25; // 1125 seconds - 18m45s
2931
private const int HighConfirmations = 50; // 2250 seconds - 37m30s
3032
private const int CirrusLowConfirmations = 30; // 480 seconds - 8m0s
31-
private const int CirrusMediumConfirmation = 70; // 1120 seconds - 18m40s
33+
private const int CirrusMediumConfirmations = 70; // 1120 seconds - 18m40s
3234
private const int CirrusHighConfirmations = 140; // 2240 seconds - 37m20s
3335

3436
private readonly NodeDeployments nodeDeployments;
3537
private readonly Dictionary<DepositRetrievalType, int> legacyRetrievalTypeConfirmations;
3638
private readonly Dictionary<DepositRetrievalType, int> retrievalTypeConfirmations;
3739
private readonly Network network;
40+
private readonly IMaturedBlocksSyncManager maturedBlocksSyncManager;
41+
private readonly ICounterChainSettings counterChainSettings;
42+
private readonly IFederatedPegSettings federatedPegSettings;
3843

39-
public RetrievalTypeConfirmations(Network network, NodeDeployments nodeDeployments, IFederatedPegSettings federatedPegSettings)
44+
public RetrievalTypeConfirmations(Network network, NodeDeployments nodeDeployments, IFederatedPegSettings federatedPegSettings, IMaturedBlocksSyncManager maturedBlocksSyncManager, ICounterChainSettings counterChainSettings)
4045
{
4146
this.nodeDeployments = nodeDeployments;
4247
this.network = network;
48+
this.maturedBlocksSyncManager = maturedBlocksSyncManager;
49+
this.counterChainSettings = counterChainSettings;
50+
this.federatedPegSettings = federatedPegSettings;
4351
this.legacyRetrievalTypeConfirmations = new Dictionary<DepositRetrievalType, int>
4452
{
4553
[DepositRetrievalType.Small] = federatedPegSettings.MinimumConfirmationsSmallDeposits,
4654
[DepositRetrievalType.Normal] = federatedPegSettings.MinimumConfirmationsNormalDeposits,
4755
[DepositRetrievalType.Large] = federatedPegSettings.MinimumConfirmationsLargeDeposits
4856
};
4957

58+
this.retrievalTypeConfirmations = new Dictionary<DepositRetrievalType, int>()
59+
{
60+
[DepositRetrievalType.Small] = federatedPegSettings.IsMainChain ? LowConfirmations : CirrusLowConfirmations,
61+
[DepositRetrievalType.Normal] = federatedPegSettings.IsMainChain ? MediumConfirmations : CirrusMediumConfirmations,
62+
[DepositRetrievalType.Large] = federatedPegSettings.IsMainChain ? HighConfirmations : CirrusHighConfirmations
63+
};
64+
5065
if (federatedPegSettings.IsMainChain)
5166
{
5267
this.legacyRetrievalTypeConfirmations[DepositRetrievalType.Distribution] = federatedPegSettings.MinimumConfirmationsDistributionDeposits;
5368
this.legacyRetrievalTypeConfirmations[DepositRetrievalType.ConversionSmall] = federatedPegSettings.MinimumConfirmationsSmallDeposits;
5469
this.legacyRetrievalTypeConfirmations[DepositRetrievalType.ConversionNormal] = federatedPegSettings.MinimumConfirmationsNormalDeposits;
5570
this.legacyRetrievalTypeConfirmations[DepositRetrievalType.ConversionLarge] = federatedPegSettings.MinimumConfirmationsLargeDeposits;
56-
}
5771

58-
if (this.network.Name.StartsWith("Cirrus"))
59-
{
60-
this.retrievalTypeConfirmations = new Dictionary<DepositRetrievalType, int>
61-
{
62-
[DepositRetrievalType.Small] = CirrusLowConfirmations,
63-
[DepositRetrievalType.Normal] = CirrusMediumConfirmation,
64-
[DepositRetrievalType.Large] = CirrusHighConfirmations
65-
};
66-
67-
if (federatedPegSettings.IsMainChain)
68-
{
69-
this.retrievalTypeConfirmations[DepositRetrievalType.Distribution] = CirrusHighConfirmations;
70-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionSmall] = CirrusLowConfirmations;
71-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionNormal] = CirrusMediumConfirmation;
72-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionLarge] = CirrusHighConfirmations;
73-
}
74-
}
75-
else
76-
{
77-
this.retrievalTypeConfirmations = new Dictionary<DepositRetrievalType, int>()
78-
{
79-
[DepositRetrievalType.Small] = LowConfirmations,
80-
[DepositRetrievalType.Normal] = MediumConfirmations,
81-
[DepositRetrievalType.Large] = HighConfirmations
82-
};
83-
84-
if (federatedPegSettings.IsMainChain)
85-
{
86-
this.retrievalTypeConfirmations[DepositRetrievalType.Distribution] = HighConfirmations;
87-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionSmall] = LowConfirmations;
88-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionNormal] = MediumConfirmations;
89-
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionLarge] = HighConfirmations;
90-
}
72+
this.retrievalTypeConfirmations[DepositRetrievalType.Distribution] = HighConfirmations;
73+
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionSmall] = LowConfirmations;
74+
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionNormal] = MediumConfirmations;
75+
this.retrievalTypeConfirmations[DepositRetrievalType.ConversionLarge] = HighConfirmations;
9176
}
9277
}
9378

79+
/// <inheritdoc/>
9480
public int MaximumConfirmationsAtMaturityHeight(int maturityHeight)
9581
{
9682
if (maturityHeight < this.Release1300ActivationHeight)
@@ -99,8 +85,7 @@ public int MaximumConfirmationsAtMaturityHeight(int maturityHeight)
9985
return this.retrievalTypeConfirmations.Values.Max();
10086
}
10187

102-
private int Release1300ActivationHeight => (this.nodeDeployments?.BIP9.ArraySize > 0) ? this.nodeDeployments.BIP9.ActivationHeightProviders[0 /* Release 1300 */].ActivationHeight : 0;
103-
88+
/// <inheritdoc/>
10489
public int GetDepositConfirmations(int depositHeight, DepositRetrievalType retrievalType)
10590
{
10691
// Keep everything maturity-height-centric. Otherwise the way we use MaximumConfirmationsAtMaturityHeight will have to change as well.
@@ -110,14 +95,31 @@ public int GetDepositConfirmations(int depositHeight, DepositRetrievalType retri
11095
return this.retrievalTypeConfirmations[retrievalType];
11196
}
11297

98+
/// <inheritdoc/>
11399
public int GetDepositMaturityHeight(int depositHeight, DepositRetrievalType retrievalType)
114100
{
115101
return depositHeight + GetDepositConfirmations(depositHeight, retrievalType);
116102
}
117103

104+
/// <inheritdoc/>
118105
public DepositRetrievalType[] GetRetrievalTypes()
119106
{
120107
return this.retrievalTypeConfirmations.Keys.ToArray();
121108
}
109+
110+
private int Release1300ActivationHeight
111+
{
112+
get
113+
{
114+
if (!this.federatedPegSettings.IsMainChain)
115+
return (this.nodeDeployments?.BIP9.ArraySize > 0) ? this.nodeDeployments.BIP9.ActivationHeightProviders[0 /* Release 1300 */].ActivationHeight : 0;
116+
117+
// This code is running on the main chain.
118+
if (this.counterChainSettings.CounterChainNetwork.Consensus.BIP9Deployments.Length == 0)
119+
return 0;
120+
121+
return this.maturedBlocksSyncManager.GetMainChainActivationHeight();
122+
}
123+
}
122124
}
123125
}

0 commit comments

Comments
 (0)