Commit 47bc6254 authored by Sergei Zubov's avatar Sergei Zubov

Improve code quality

parent 6cb9d329
...@@ -14,5 +14,10 @@ namespace NBitcoin ...@@ -14,5 +14,10 @@ namespace NBitcoin
{ {
return txInList.Where(p => p.PrevOut.Hash == uint256.Zero).Select(p => p.PrevOut.N); return txInList.Where(p => p.PrevOut.Hash == uint256.Zero).Select(p => p.PrevOut.N);
} }
public static bool IsChangePointer(this TxIn txInList)
{
return txInList.PrevOut.Hash == uint256.Zero;
}
} }
} }
\ No newline at end of file
...@@ -5,7 +5,7 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -5,7 +5,7 @@ namespace Stratis.Bitcoin.Features.Consensus
/// <summary> /// <summary>
/// A class that holds consensus errors. /// A class that holds consensus errors.
/// </summary> /// </summary>
public static class ConsensusErrors public static partial class ConsensusErrors
{ {
public static readonly ConsensusError InvalidPrevTip = new ConsensusError("invalid-prev-tip", "invalid previous tip"); public static readonly ConsensusError InvalidPrevTip = new ConsensusError("invalid-prev-tip", "invalid previous tip");
public static readonly ConsensusError HighHash = new ConsensusError("high-hash", "proof of work failed"); public static readonly ConsensusError HighHash = new ConsensusError("high-hash", "proof of work failed");
......
...@@ -28,7 +28,6 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -28,7 +28,6 @@ namespace Stratis.Bitcoin.Features.Consensus
/// <param name="network">The network.</param> /// <param name="network">The network.</param>
public virtual int GetStakeMinConfirmations(int height, Network network) public virtual int GetStakeMinConfirmations(int height, Network network)
{ {
return 0;
if (network.IsTest()) if (network.IsTest())
return height < CoinstakeMinConfirmationActivationHeightTestnet ? 10 : 20; return height < CoinstakeMinConfirmationActivationHeightTestnet ? 10 : 20;
......
using Stratis.Bitcoin.Consensus;
namespace Stratis.Bitcoin.Features.Consensus
{
public static partial class ConsensusErrors
{
public static readonly ConsensusError BadBlockNoFeeOutput = new ConsensusError("bad-blk-feeoutput", "no fee output in coinbase or coinstake transactions");
}
}
\ No newline at end of file
...@@ -4,25 +4,41 @@ using Stratis.Bitcoin.Consensus; ...@@ -4,25 +4,41 @@ using Stratis.Bitcoin.Consensus;
namespace Stratis.Bitcoin.Features.Consensus namespace Stratis.Bitcoin.Features.Consensus
{ {
/// <inheritdoc /> public interface IDeStreamRuleContext
public class DeStreamPosRuleContext : PosRuleContext
{ {
internal DeStreamPosRuleContext() /// <summary>
/// ScriptPubKeys of inputs spent in transaction
/// </summary>
List<Script> InputScriptPubKeys { get; set; }
/// <summary>
/// Sum of inputs spent in transaction
/// </summary>
Money TotalIn { get; set; }
}
/// <inheritdoc cref="PosRuleContext" />
public class DeStreamRuleContext : PosRuleContext, IDeStreamRuleContext
{
internal DeStreamRuleContext()
{ {
} }
public DeStreamPosRuleContext(ValidationContext validationContext, NBitcoin.Consensus consensus, public DeStreamRuleContext(ValidationContext validationContext, NBitcoin.Consensus consensus,
ChainedHeader consensusTip) : base(validationContext, consensus, consensusTip) ChainedHeader consensusTip) : base(validationContext, consensus, consensusTip)
{ {
} }
/// <inheritdoc />
public List<Script> InputScriptPubKeys { get; set; } public List<Script> InputScriptPubKeys { get; set; }
/// <inheritdoc />
public Money TotalIn { get; set; } public Money TotalIn { get; set; }
} }
/// <inheritdoc /> /// <inheritdoc cref="PowRuleContext" />
public class DeStreamPowRuleContext : PowRuleContext public class DeStreamPowRuleContext : PowRuleContext, IDeStreamRuleContext
{ {
internal DeStreamPowRuleContext() internal DeStreamPowRuleContext()
{ {
...@@ -33,8 +49,10 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -33,8 +49,10 @@ namespace Stratis.Bitcoin.Features.Consensus
{ {
} }
/// <inheritdoc />
public List<Script> InputScriptPubKeys { get; set; } public List<Script> InputScriptPubKeys { get; set; }
/// <inheritdoc />
public Money TotalIn { get; set; } public Money TotalIn { get; set; }
} }
} }
\ No newline at end of file
...@@ -7,12 +7,18 @@ using Stratis.Bitcoin.Consensus.Rules; ...@@ -7,12 +7,18 @@ using Stratis.Bitcoin.Consensus.Rules;
namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
{ {
/// <summary>
/// A rule that verifies fee is charged from all spent funds and transferred to <see cref="Network.DeStreamWallet"/>
/// </summary>
[ExecutionRule] [ExecutionRule]
public class DeStreamBlockFeeRule : ConsensusRule public class DeStreamBlockFeeRule : ConsensusRule
{ {
public override Task RunAsync(RuleContext context) public override Task RunAsync(RuleContext context)
{ {
// Actual fee is funds that are transferred to fee wallet in mined/staked block
long actualFee = this.GetActualFee(context.ValidationContext.Block); long actualFee = this.GetActualFee(context.ValidationContext.Block);
// Expected fee is charged from all moved funds (not change)
long expectedFee; long expectedFee;
switch (context) switch (context)
{ {
...@@ -20,16 +26,17 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -20,16 +26,17 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
expectedFee = this.GetExpectedFee(context.ValidationContext.Block, deStreamPowRuleContext.TotalIn, expectedFee = this.GetExpectedFee(context.ValidationContext.Block, deStreamPowRuleContext.TotalIn,
deStreamPowRuleContext.InputScriptPubKeys); deStreamPowRuleContext.InputScriptPubKeys);
break; break;
case DeStreamPosRuleContext deStreamPosRuleContext: case DeStreamRuleContext deStreamPosRuleContext:
expectedFee = this.GetExpectedFee(context.ValidationContext.Block, deStreamPosRuleContext.TotalIn, expectedFee = this.GetExpectedFee(context.ValidationContext.Block, deStreamPosRuleContext.TotalIn,
deStreamPosRuleContext.InputScriptPubKeys); deStreamPosRuleContext.InputScriptPubKeys);
break; break;
default: default:
throw new Exception(); throw new NotSupportedException(
$"Rule context must be {nameof(DeStreamPowRuleContext)} or {nameof(DeStreamRuleContext)}");
} }
if (Math.Abs(actualFee - expectedFee) > Money.CENT) if (Math.Abs(actualFee - expectedFee) > Money.CENT)
throw new Exception(); ConsensusErrors.BadTransactionFeeOutOfRange.Throw();
return Task.CompletedTask; return Task.CompletedTask;
} }
...@@ -40,32 +47,21 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -40,32 +47,21 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
.Where(p => this.Parent.Network.IsDeStreamAddress(p.ScriptPubKey .Where(p => this.Parent.Network.IsDeStreamAddress(p.ScriptPubKey
.GetDestinationAddress(this.Parent.Network)?.ToString())).ToList(); .GetDestinationAddress(this.Parent.Network)?.ToString())).ToList();
if (outputsToFeeWallet.Count() != 1) if (outputsToFeeWallet.Count != 1)
throw new Exception(); ConsensusErrors.BadBlockNoFeeOutput.Throw();
return outputsToFeeWallet.Single().Value; return outputsToFeeWallet.Single().Value;
} }
private long GetExpectedFee(Block block, Money totalIn, ICollection<Script> inputScriptPubKeys) private long GetExpectedFee(Block block, Money totalIn, ICollection<Script> inputScriptPubKeys)
{ {
long totalFee = 0; return block.Transactions.Where(p => !p.IsCoinBase && !p.IsCoinStake).Sum(p => this.GetFeeInTransaction(p,
foreach (Transaction transaction in block.Transactions.Where(p => !p.IsCoinBase && !p.IsCoinStake)) totalIn, p.Outputs
{ .Select(q => q.ScriptPubKey).Intersect(inputScriptPubKeys)
IList<Script> changeScriptPubKeys = transaction.Outputs .Concat(p.Inputs.GetChangePointers()
.Select(q => .Select(q => p.Outputs[q].ScriptPubKey))
q.ScriptPubKey)
.Intersect(inputScriptPubKeys)
.Concat(transaction.Inputs.GetChangePointers()
.Select(p => transaction.Outputs[p].ScriptPubKey))
.Distinct() .Distinct()
.ToList(); .ToList()));
long feeInTransaction = this.GetFeeInTransaction(transaction, totalIn, changeScriptPubKeys);
totalFee += feeInTransaction;
}
return totalFee;
} }
private long GetFeeInTransaction(Transaction transaction, Money totalIn, private long GetFeeInTransaction(Transaction transaction, Money totalIn,
...@@ -75,7 +71,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -75,7 +71,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
.Where(p => !changeScriptPubKeys.Contains(p.ScriptPubKey)) .Where(p => !changeScriptPubKeys.Contains(p.ScriptPubKey))
.Sum(p => p.Value) * this.Parent.Network.FeeRate; .Sum(p => p.Value) * this.Parent.Network.FeeRate;
if (Math.Abs(totalIn.Satoshi - transaction.TotalOut.Satoshi - feeInTransaction) > Money.CENT) if (Math.Abs(totalIn.Satoshi - transaction.TotalOut.Satoshi - feeInTransaction) > Money.CENT)
throw new Exception(); ConsensusErrors.BadTransactionFeeOutOfRange.Throw();
return (long) (feeInTransaction * this.Parent.Network.DeStreamFeePart); return (long) (feeInTransaction * this.Parent.Network.DeStreamFeePart);
} }
......
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
...@@ -9,6 +10,9 @@ using Stratis.Bitcoin.Utilities; ...@@ -9,6 +10,9 @@ using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
{ {
/// <summary>
/// CoinViewRule that prevents verifing ChangePointer input
/// </summary>
public abstract class DeStreamCoinViewRule : CoinViewRule public abstract class DeStreamCoinViewRule : CoinViewRule
{ {
public override async Task RunAsync(RuleContext context) public override async Task RunAsync(RuleContext context)
...@@ -45,7 +49,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -45,7 +49,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
// be in ConnectBlock because they require the UTXO set. // be in ConnectBlock because they require the UTXO set.
for (int j = 0; j < tx.Inputs.Count; j++) for (int j = 0; j < tx.Inputs.Count; j++)
{ {
prevheights[j] = tx.Inputs[j].PrevOut.Hash == uint256.Zero prevheights[j] = tx.Inputs[j].IsChangePointer()
? 0 ? 0
: (int) view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height; : (int) view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
} }
...@@ -75,7 +79,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -75,7 +79,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
var txData = new PrecomputedTransactionData(tx); var txData = new PrecomputedTransactionData(tx);
for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++) for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
{ {
if (tx.Inputs[inputIndex].PrevOut.Hash == uint256.Zero) if (tx.Inputs[inputIndex].IsChangePointer())
continue; continue;
this.Parent.PerformanceCounter.AddProcessedInputs(1); this.Parent.PerformanceCounter.AddProcessedInputs(1);
...@@ -126,6 +130,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -126,6 +130,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
this.Logger.LogTrace("(-)"); this.Logger.LogTrace("(-)");
} }
/// <inheritdoc />
public override void CheckInputs(Transaction transaction, UnspentOutputSet inputs, int spendHeight) public override void CheckInputs(Transaction transaction, UnspentOutputSet inputs, int spendHeight)
{ {
this.Logger.LogTrace("({0}:{1})", nameof(spendHeight), spendHeight); this.Logger.LogTrace("({0}:{1})", nameof(spendHeight), spendHeight);
...@@ -175,6 +180,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -175,6 +180,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
this.Logger.LogTrace("(-)"); this.Logger.LogTrace("(-)");
} }
/// <inheritdoc />
public override long GetTransactionSignatureOperationCost(Transaction transaction, UnspentOutputSet inputs, public override long GetTransactionSignatureOperationCost(Transaction transaction, UnspentOutputSet inputs,
DeploymentFlags flags) DeploymentFlags flags)
{ {
...@@ -185,8 +191,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -185,8 +191,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
return signatureOperationCost; return signatureOperationCost;
if (flags.ScriptFlags.HasFlag(ScriptVerify.P2SH)) if (flags.ScriptFlags.HasFlag(ScriptVerify.P2SH))
{
signatureOperationCost += this.GetP2SHSignatureOperationsCount(transaction, inputs) * signatureOperationCost += this.GetP2SHSignatureOperationsCount(transaction, inputs) *
this.PowConsensusOptions.WitnessScaleFactor; this.PowConsensusOptions.WitnessScaleFactor;
}
signatureOperationCost += (from t in transaction.Inputs.RemoveChangePointer() signatureOperationCost += (from t in transaction.Inputs.RemoveChangePointer()
let prevout = inputs.GetOutputFor(t) let prevout = inputs.GetOutputFor(t)
...@@ -195,6 +203,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -195,6 +203,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
return signatureOperationCost; return signatureOperationCost;
} }
/// <inheritdoc />
protected override uint GetP2SHSignatureOperationsCount(Transaction transaction, UnspentOutputSet inputs) protected override uint GetP2SHSignatureOperationsCount(Transaction transaction, UnspentOutputSet inputs)
{ {
if (transaction.IsCoinBase) if (transaction.IsCoinBase)
...@@ -211,8 +220,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -211,8 +220,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
return sigOps; return sigOps;
} }
///<inheritdoc />
protected override void UpdateUTXOSet(RuleContext context, Transaction transaction) protected override void UpdateUTXOSet(RuleContext context, Transaction transaction)
{ {
// Saves script pub keys and total amount of spent inputs to context
this.Logger.LogTrace("()"); this.Logger.LogTrace("()");
ChainedHeader index = context.ValidationContext.ChainedHeader; ChainedHeader index = context.ValidationContext.ChainedHeader;
...@@ -225,11 +237,14 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -225,11 +237,14 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
.Select(p => view.GetOutputFor(p).ScriptPubKey)); .Select(p => view.GetOutputFor(p).ScriptPubKey));
deStreamPowRuleContext.TotalIn = view.GetValueIn(transaction); deStreamPowRuleContext.TotalIn = view.GetValueIn(transaction);
break; break;
case DeStreamPosRuleContext deStreamPosRuleContext: case DeStreamRuleContext deStreamPosRuleContext:
deStreamPosRuleContext.InputScriptPubKeys.AddRange(transaction.Inputs.RemoveChangePointer() deStreamPosRuleContext.InputScriptPubKeys.AddRange(transaction.Inputs.RemoveChangePointer()
.Select(p => view.GetOutputFor(p).ScriptPubKey)); .Select(p => view.GetOutputFor(p).ScriptPubKey));
deStreamPosRuleContext.TotalIn = view.GetValueIn(transaction); deStreamPosRuleContext.TotalIn = view.GetValueIn(transaction);
break; break;
default:
throw new NotSupportedException(
$"Rule context must be {nameof(DeStreamPowRuleContext)} or {nameof(DeStreamRuleContext)}");
} }
view.Update(transaction, index.Height); view.Update(transaction, index.Height);
......
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
...@@ -25,9 +26,12 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -25,9 +26,12 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
case DeStreamPowRuleContext deStreamPowRuleContext: case DeStreamPowRuleContext deStreamPowRuleContext:
deStreamPowRuleContext.InputScriptPubKeys = new List<Script>(); deStreamPowRuleContext.InputScriptPubKeys = new List<Script>();
break; break;
case DeStreamPosRuleContext deStreamPosRuleContext: case DeStreamRuleContext deStreamPosRuleContext:
deStreamPosRuleContext.InputScriptPubKeys = new List<Script>(); deStreamPosRuleContext.InputScriptPubKeys = new List<Script>();
break; break;
default:
throw new NotSupportedException(
$"Rule context must be {nameof(DeStreamPowRuleContext)} or {nameof(DeStreamRuleContext)}");
} }
using (new StopwatchDisposable(o => this.Parent.PerformanceCounter.AddUTXOFetchingTime(o))) using (new StopwatchDisposable(o => this.Parent.PerformanceCounter.AddUTXOFetchingTime(o)))
......
...@@ -40,7 +40,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules ...@@ -40,7 +40,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules
public override RuleContext CreateRuleContext(ValidationContext validationContext, ChainedHeader consensusTip) public override RuleContext CreateRuleContext(ValidationContext validationContext, ChainedHeader consensusTip)
{ {
return new DeStreamPosRuleContext(validationContext, this.Network.Consensus, consensusTip); return new DeStreamRuleContext(validationContext, this.Network.Consensus, consensusTip);
} }
} }
} }
\ No newline at end of file
...@@ -10,6 +10,9 @@ using Stratis.Bitcoin.Utilities; ...@@ -10,6 +10,9 @@ using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.MemoryPool namespace Stratis.Bitcoin.Features.MemoryPool
{ {
/// <summary>
/// Creates <see cref="DeStreamUnspentOutputSet"/> and ChangePointer input
/// </summary>
public class DeStreamMempoolCoinView : MempoolCoinView public class DeStreamMempoolCoinView : MempoolCoinView
{ {
public DeStreamMempoolCoinView(CoinView inner, ITxMempool memPool, SchedulerLock mempoolLock, IMempoolValidator mempoolValidator) : base(inner, memPool, mempoolLock, mempoolValidator) public DeStreamMempoolCoinView(CoinView inner, ITxMempool memPool, SchedulerLock mempoolLock, IMempoolValidator mempoolValidator) : base(inner, memPool, mempoolLock, mempoolValidator)
......
...@@ -7,6 +7,9 @@ using Stratis.Bitcoin.Utilities; ...@@ -7,6 +7,9 @@ using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.MemoryPool namespace Stratis.Bitcoin.Features.MemoryPool
{ {
/// <summary>
/// Creates <see cref="DeStreamMempoolCoinView"/>
/// </summary>
public class DeStreamMempoolManager : MempoolManager public class DeStreamMempoolManager : MempoolManager
{ {
public DeStreamMempoolManager(MempoolSchedulerLock mempoolLock, ITxMempool memPool, IMempoolValidator validator, IDateTimeProvider dateTimeProvider, MempoolSettings mempoolSettings, IMempoolPersistence mempoolPersistence, CoinView coinView, ILoggerFactory loggerFactory, Network network) : base(mempoolLock, memPool, validator, dateTimeProvider, mempoolSettings, mempoolPersistence, coinView, loggerFactory, network) public DeStreamMempoolManager(MempoolSchedulerLock mempoolLock, ITxMempool memPool, IMempoolValidator validator, IDateTimeProvider dateTimeProvider, MempoolSettings mempoolSettings, IMempoolPersistence mempoolPersistence, CoinView coinView, ILoggerFactory loggerFactory, Network network) : base(mempoolLock, memPool, validator, dateTimeProvider, mempoolSettings, mempoolPersistence, coinView, loggerFactory, network)
......
...@@ -12,6 +12,9 @@ using Stratis.Bitcoin.Utilities; ...@@ -12,6 +12,9 @@ using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.MemoryPool namespace Stratis.Bitcoin.Features.MemoryPool
{ {
/// <summary>
/// Creates <see cref="DeStreamMempoolCoinView"/> and prevents verifing ChangePointer input
/// </summary>
public class DeStreamMempoolValidator : MempoolValidator public class DeStreamMempoolValidator : MempoolValidator
{ {
public DeStreamMempoolValidator(ITxMempool memPool, MempoolSchedulerLock mempoolLock, public DeStreamMempoolValidator(ITxMempool memPool, MempoolSchedulerLock mempoolLock,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment