Skip to content

Commit 2273fd4

Browse files
authored
Add XDS network (#83)
* First commit copy of stratis * Add XDS network * Get network to sync. and fix a consensus bug * Fix create genesis bug * Fix dust error
1 parent 138ad7c commit 2273fd4

71 files changed

Lines changed: 2025 additions & 280 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Blockcore.Features.ColdStaking.Tests/ColdStakingControllerTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ private void MockStakeChain()
108108
{
109109
Flags = BlockFlag.BLOCK_PROOF_OF_STAKE,
110110
StakeModifierV2 = 0,
111-
StakeTime = (this.chainIndexer.Tip.Header.Time + 60) & ~PosConsensusOptions.StakeTimestampMask
111+
StakeTime = (this.chainIndexer.Tip.Header.Time + 60) & ~this.Network.Consensus.ProofOfStakeTimestampMask
112112
});
113113
}
114114

src/Blockcore.Features.ColdStaking/ColdStakingManager.cs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler wa
360360
coldPubKeyHash = new BitcoinWitPubKeyAddress(coldWalletAddress, wallet.Network).Hash.AsKeyId();
361361
destination = ColdStakingScriptTemplate.Instance.GenerateScriptPubKey(hotPubKeyHash, coldPubKeyHash);
362362

363-
if(payToScript)
363+
if (payToScript)
364364
{
365365
HdAddress address = coldAddress ?? hotAddress;
366366
address.RedeemScript = destination;
@@ -382,7 +382,7 @@ internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler wa
382382
}
383383

384384
// Only normal accounts should be allowed.
385-
if (!this.GetAccounts(walletName).Any(a => a.Name == walletAccount))
385+
if (this.GetAccounts(walletName).All(a => a.Name != walletAccount))
386386
{
387387
this.logger.LogTrace("(-)[COLDSTAKE_ACCOUNT_NOT_FOUND]");
388388
throw new WalletException($"Can't find wallet account '{walletAccount}'.");
@@ -403,20 +403,22 @@ internal Transaction GetColdStakingSetupTransaction(IWalletTransactionHandler wa
403403
{
404404
// In the case of P2SH and P2WSH, to avoid the possibility of lose of funds
405405
// we add an opreturn with the hot and cold key hashes to the setup transaction
406-
// this will allow a user to recreate the redeem script of the output in case they lose
407-
// access to one of the keys.
408-
// The special marker will help a wallet that is tracking cold staking accounts to monitor
409-
// the hot and cold keys, if a special marker is found then the keys are in the opreturn are checked
406+
// this will allow a user to recreate the redeem script of the output in case they lose
407+
// access to one of the keys.
408+
// The special marker will help a wallet that is tracking cold staking accounts to monitor
409+
// the hot and cold keys, if a special marker is found then the keys are in the opreturn are checked
410410
// against the current wallet, if found and validated the wallet will track that ScriptPubKey
411411

412412
var opreturnKeys = new List<byte>();
413413
opreturnKeys.AddRange(hotPubKeyHash.ToBytes());
414414
opreturnKeys.AddRange(coldPubKeyHash.ToBytes());
415-
415+
416416
context.OpReturnRawData = opreturnKeys.ToArray();
417-
//context.OpReturnAmount = Money.Satoshis(1); // mandatory fee must be paid.
418-
419-
// The P2SH and P2WSH hide the cold stake keys in the script hash so the wallet cannot track
417+
var template = this.network.StandardScriptsRegistry.GetScriptTemplates.OfType<TxNullDataTemplate>().First();
418+
if (template.MinRequiredSatoshiFee > 0)
419+
context.OpReturnAmount = Money.Satoshis(template.MinRequiredSatoshiFee); // mandatory fee must be paid.
420+
421+
// The P2SH and P2WSH hide the cold stake keys in the script hash so the wallet cannot track
420422
// the ouputs based on the derived keys when the trx is subbmited to the network.
421423
// So we add the output script manually.
422424
}
@@ -611,7 +613,7 @@ public override void TransactionFoundInternal(Script script, Func<HdAccount, boo
611613
/// <summary>
612614
/// The purpose of this method is to try to identify the P2SH and P2WSH that are coldstake outputs for this wallet
613615
/// We look for an opreturn script that is created when seting up a P2SH and P2WSH cold stake trx
614-
/// if we find any then try to find the keys and track the script before calling in to the main wallet.
616+
/// if we find any then try to find the keys and track the script before calling in to the main wallet.
615617
/// </summary>
616618
/// <inheritdoc/>
617619
public override bool ProcessTransaction(Transaction transaction, int? blockHeight = null, Block block = null, bool isPropagated = true)
@@ -628,7 +630,7 @@ public override bool ProcessTransaction(Transaction transaction, int? blockHeigh
628630
if (data[0].Length == 40)
629631
{
630632
HdAddress address = null;
631-
633+
632634
Span<byte> span = data[0].AsSpan();
633635
var hotPubKey = new KeyId(span.Slice(0, 20).ToArray());
634636
var coldPubKey = new KeyId(span.Slice(20, 20).ToArray());
@@ -642,11 +644,11 @@ public override bool ProcessTransaction(Transaction transaction, int? blockHeigh
642644
// Find the type of script for the opreturn (P2SH or P2WSH)
643645
foreach (TxOut utxoInner in transaction.Outputs)
644646
{
645-
if(utxoInner.ScriptPubKey == destination.Hash.ScriptPubKey)
647+
if (utxoInner.ScriptPubKey == destination.Hash.ScriptPubKey)
646648
{
647-
if (!this.scriptToAddressLookup.TryGetValue(destination.Hash.ScriptPubKey,out HdAddress _))
649+
if (!this.scriptToAddressLookup.TryGetValue(destination.Hash.ScriptPubKey, out HdAddress _))
648650
this.scriptToAddressLookup[destination.Hash.ScriptPubKey] = address;
649-
651+
650652
break;
651653
}
652654

@@ -673,9 +675,9 @@ protected override void AddAddressToIndex(HdAddress address)
673675
{
674676
base.AddAddressToIndex(address);
675677

676-
if(address.RedeemScript != null)
678+
if (address.RedeemScript != null)
677679
{
678-
// The redeem script has no indication on the script type (P2SH or P2WSH),
680+
// The redeem script has no indication on the script type (P2SH or P2WSH),
679681
// so we track both, add both to the indexer then.
680682

681683
if (!this.scriptToAddressLookup.TryGetValue(address.RedeemScript.Hash.ScriptPubKey, out HdAddress _))
@@ -686,4 +688,4 @@ protected override void AddAddressToIndex(HdAddress address)
686688
}
687689
}
688690
}
689-
}
691+
}

src/Blockcore.Features.ColdStaking/Controllers/ColdStakingWalletRPCController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Blockcore.Consensus;
22
using Blockcore.Features.BlockStore;
33
using Blockcore.Features.Wallet;
4+
using Blockcore.Features.Wallet.Controllers;
45
using Blockcore.Features.Wallet.Interfaces;
56
using Blockcore.Interfaces;
67
using Microsoft.AspNetCore.Mvc;

src/Blockcore.Features.Consensus.Tests/Rules/CommonRules/PosCoinViewRuleTest.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private async Task<ConsensusManager> CreateConsensusManagerAsync(Dictionary<OutP
6868
new Mock<IPeerBanning>().Object, initialBlockDownloadState, this.ChainIndexer, new Mock<IBlockPuller>().Object, new Mock<IBlockStore>().Object,
6969
new Mock<IConnectionManager>().Object, new Mock<INodeStats>().Object, new Mock<INodeLifetime>().Object, this.consensusSettings, this.dateTimeProvider.Object);
7070

71-
// Mock the coinviews "FetchCoinsAsync" method. We will use the "unspentOutputs" dictionary to track spendable outputs.
71+
// Mock the coinviews "FetchCoinsAsync" method. We will use the "unspentOutputs" dictionary to track spendable outputs.
7272
this.coinView.Setup(d => d.FetchCoins(It.IsAny<OutPoint[]>()))
7373
.Returns((OutPoint[] txIds) =>
7474
{
@@ -106,7 +106,7 @@ private async Task<ConsensusManager> CreateConsensusManagerAsync(Dictionary<OutP
106106
{
107107
Flags = BlockFlag.BLOCK_PROOF_OF_STAKE,
108108
StakeModifierV2 = 0,
109-
StakeTime = (this.ChainIndexer.Tip.Header.Time + 60) & ~PosConsensusOptions.StakeTimestampMask
109+
StakeTime = (this.ChainIndexer.Tip.Header.Time + 60) & ~this.network.Consensus.ProofOfStakeTimestampMask
110110
});
111111

112112
// Since we are mocking the chainState ensure that the BlockStoreTip returns a usable value.
@@ -142,7 +142,6 @@ public async Task PosCoinViewRuleFailsAsync()
142142

143143
ConsensusManager consensusManager = await this.CreateConsensusManagerAsync(unspentOutputs);
144144

145-
146145
// The keys used by miner 1 and miner 2.
147146
var minerKey1 = new Key();
148147
var minerKey2 = new Key();
@@ -166,13 +165,13 @@ public async Task PosCoinViewRuleFailsAsync()
166165
// Create a previous transaction with scriptPubKey outputs.
167166
Transaction prevTransaction = this.network.CreateTransaction();
168167

169-
uint blockTime = (this.ChainIndexer.Tip.Header.Time + 60) & ~PosConsensusOptions.StakeTimestampMask;
168+
uint blockTime = (this.ChainIndexer.Tip.Header.Time + 60) & ~this.network.Consensus.ProofOfStakeTimestampMask;
170169

171170
// To avoid violating the transaction timestamp consensus rule
172171
// we need to ensure that the transaction used for the coinstake's
173172
// input occurs well before the block time (as the coinstake time
174173
// is set to the block time)
175-
if(prevTransaction is IPosTransactionWithTime posTrx)
174+
if (prevTransaction is IPosTransactionWithTime posTrx)
176175
posTrx.Time = blockTime - 100;
177176

178177
// Coins sent to miner 2.

src/Blockcore.Features.Consensus/Rules/CommonRules/PosTimeMaskRule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public override Task RunAsync(RuleContext context)
7171
/// <returns><c>true</c> if block timestamp is equal to transaction timestamp, <c>false</c> otherwise.</returns>
7272
private bool CheckCoinStakeTimestamp(long blockTime)
7373
{
74-
return (blockTime & PosConsensusOptions.StakeTimestampMask) == 0;
74+
return (blockTime & this.Parent.Network.Consensus.ProofOfStakeTimestampMask) == 0;
7575
}
7676
}
7777
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ private void CheckHeaderAndCoinstakeTimes(ProvenBlockHeader header)
178178
}
179179
}
180180

181-
if ((header.Time & PosConsensusOptions.StakeTimestampMask) != 0)
181+
if ((header.Time & this.Parent.Network.Consensus.ProofOfStakeTimestampMask) != 0)
182182
{
183183
this.Logger.LogTrace("(-)[BAD_TIME]");
184184
ConsensusErrors.StakeTimeViolation.Throw();

src/Blockcore.Features.Consensus/Rules/UtxosetRules/CheckPosUtxosetRule.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Blockcore.Features.Consensus.Rules.UtxosetRules
1212
/// <summary>
1313
/// Proof of stake override for the coinview rules - BIP68, MaxSigOps and BlockReward checks.
1414
/// </summary>
15-
public sealed class CheckPosUtxosetRule : CheckUtxosetRule
15+
public class CheckPosUtxosetRule : CheckUtxosetRule
1616
{
1717
/// <summary>Provides functionality for checking validity of PoS blocks.</summary>
1818
private IStakeValidator stakeValidator;
@@ -21,7 +21,7 @@ public sealed class CheckPosUtxosetRule : CheckUtxosetRule
2121
private IStakeChain stakeChain;
2222

2323
/// <summary>The consensus of the parent Network.</summary>
24-
private IConsensus consensus;
24+
protected IConsensus consensus;
2525

2626
/// <inheritdoc />
2727
public override void Initialize()
@@ -203,7 +203,7 @@ public override Money GetProofOfWorkReward(int height)
203203
/// </summary>
204204
/// <param name="height">Target block height.</param>
205205
/// <returns>Miner's coin stake reward.</returns>
206-
public Money GetProofOfStakeReward(int height)
206+
public virtual Money GetProofOfStakeReward(int height)
207207
{
208208
if (this.IsPremine(height))
209209
return this.consensus.PremineReward;

src/Blockcore.Features.Consensus/StakeValidator.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public Target GetNextTargetRequired(IStakeChain stakeChain, ChainedHeader chaine
167167
}
168168

169169
// This is used in tests to allow quickly mining blocks.
170-
if (!proofOfStake && consensus.PowNoRetargeting)
170+
if (!proofOfStake && consensus.PowNoRetargeting)
171171
{
172172
this.logger.LogTrace("(-)[NO_POW_RETARGET]:'{0}'", lastPowPosBlock.Header.Bits);
173173
return lastPowPosBlock.Header.Bits;
@@ -308,11 +308,6 @@ public bool CheckStakeKernelHash(PosRuleContext context, uint headerBits, uint25
308308
// Base target.
309309
BigInteger target = new Target(headerBits).ToBigInteger();
310310

311-
// TODO: Investigate:
312-
// The POS protocol should probably put a limit on the max amount that can be staked
313-
// not a hard limit but a limit that allow any amount to be staked with a max weight value.
314-
// the max weight should not exceed the max uint256 array size (array size = 32).
315-
316311
// Weighted target.
317312
long valueIn = stakingCoins.Coins.TxOut.Value.Satoshi;
318313
BigInteger weight = BigInteger.ValueOf(valueIn);
@@ -326,7 +321,8 @@ public bool CheckStakeKernelHash(PosRuleContext context, uint headerBits, uint25
326321
{
327322
var serializer = new BitcoinStream(ms, true);
328323
serializer.ReadWrite(prevStakeModifier);
329-
serializer.ReadWrite(stakingCoins.Coins.Time);
324+
if (this.network.Consensus.PosUseTimeFieldInKernalHash) // old posv3 time field
325+
serializer.ReadWrite(stakingCoins.Coins.Time);
330326
serializer.ReadWrite(prevout.Hash);
331327
serializer.ReadWrite(prevout.N);
332328
serializer.ReadWrite(transactionTime);
@@ -358,13 +354,6 @@ public bool VerifySignature(UnspentOutput coin, Transaction txTo, int txToInN, S
358354

359355
TxIn input = txTo.Inputs[txToInN];
360356

361-
//if (input.PrevOut.N >= coin.Outputs.Length)
362-
//{
363-
// this.logger.LogTrace("(-)[OUTPUT_INCORRECT_LENGTH]");
364-
// return false;
365-
//}
366-
367-
//if (input.PrevOut.Hash != coin.TransactionId)
368357
if (input.PrevOut.Hash != coin.OutPoint.Hash)
369358
{
370359
this.logger.LogTrace("(-)[INCORRECT_TX]");
@@ -486,5 +475,4 @@ public bool CheckStakeSignature(BlockSignature signature, uint256 blockHash, Tra
486475
return verifyRes;
487476
}
488477
}
489-
}
490-
478+
}

src/Blockcore.Features.MemoryPool/MempoolPersistence.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public override int GetHashCode()
158158
/// <summary>
159159
/// Object used for persisting memory pool transactions.
160160
/// </summary>
161-
internal class MempoolPersistence : IMempoolPersistence
161+
public class MempoolPersistence : IMempoolPersistence
162162
{
163163
/// <summary>Current memory pool version number for persistence.</summary>
164164
public const ulong MempoolDumpVersion = 0;
@@ -328,4 +328,4 @@ internal IEnumerable<MempoolPersistenceEntry> LoadFromStream(Network network, St
328328
return toReturn;
329329
}
330330
}
331-
}
331+
}

src/Blockcore.Features.MemoryPool/MempoolValidator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public class MempoolValidator : IMempoolValidator
7676
public const bool DefaultPermitBareMultisig = true;
7777

7878
/// <summary>Maximum age of our tip in seconds for us to be considered current for fee estimation.</summary>
79-
private const int MaxFeeEstimationTipAge = 3 * 60 * 60;
79+
public const int MaxFeeEstimationTipAge = 3 * 60 * 60;
8080

8181
/// <summary>A lock for managing asynchronous access to memory pool.</summary>
8282
private readonly MempoolSchedulerLock mempoolLock;

0 commit comments

Comments
 (0)