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

Improve code quality

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