Commit 06fd8d31 authored by Sergei Zubov's avatar Sergei Zubov

Fix fees check in consensus

InputScriptPubKeys from different transactions could mix and corrupt
validation context. PubKeys moved from list to dictionary of lists,
with transaction hash as key.
parent 13cd7055
...@@ -9,7 +9,7 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -9,7 +9,7 @@ namespace Stratis.Bitcoin.Features.Consensus
/// <summary> /// <summary>
/// ScriptPubKeys of inputs spent in transaction /// ScriptPubKeys of inputs spent in transaction
/// </summary> /// </summary>
List<Script> InputScriptPubKeys { get; set; } IDictionary<uint256, List<Script>> InputScriptPubKeys { get; set; }
/// <summary> /// <summary>
/// Sum of inputs spent in transaction /// Sum of inputs spent in transaction
...@@ -30,7 +30,7 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -30,7 +30,7 @@ namespace Stratis.Bitcoin.Features.Consensus
} }
/// <inheritdoc /> /// <inheritdoc />
public List<Script> InputScriptPubKeys { get; set; } public IDictionary<uint256, List<Script>> InputScriptPubKeys { get; set; }
/// <inheritdoc /> /// <inheritdoc />
...@@ -50,7 +50,7 @@ namespace Stratis.Bitcoin.Features.Consensus ...@@ -50,7 +50,7 @@ namespace Stratis.Bitcoin.Features.Consensus
} }
/// <inheritdoc /> /// <inheritdoc />
public List<Script> InputScriptPubKeys { get; set; } public IDictionary<uint256, List<Script>> InputScriptPubKeys { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public IDictionary<uint256, Money> TotalIn { get; set; } = new Dictionary<uint256, Money>(); public IDictionary<uint256, Money> TotalIn { get; set; } = new Dictionary<uint256, Money>();
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -55,11 +55,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -55,11 +55,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
return outputsToFeeWallet.Single().Value; return outputsToFeeWallet.Single().Value;
} }
private long GetExpectedFee(Block block, IDictionary<uint256, Money> totalIn, ICollection<Script> inputScriptPubKeys) private long GetExpectedFee(Block block, IDictionary<uint256, Money> totalIn, IDictionary<uint256, List<Script>> inputScriptPubKeys)
{ {
return block.Transactions.Where(p => !p.IsCoinBase && !p.IsCoinStake).Sum(p => this.GetFeeInTransaction(p, return block.Transactions.Where(p => !p.IsCoinBase && !p.IsCoinStake).Sum(p => this.GetFeeInTransaction(p,
totalIn[p.GetHash()], p.Outputs totalIn[p.GetHash()], p.Outputs
.Select(q => q.ScriptPubKey).Intersect(inputScriptPubKeys) .Select(q => q.ScriptPubKey).Intersect(inputScriptPubKeys[p.GetHash()])
.Concat(p.Inputs.GetChangePointers() .Concat(p.Inputs.GetChangePointers()
.Select(q => p.Outputs[q].ScriptPubKey)) .Select(q => p.Outputs[q].ScriptPubKey))
.Distinct() .Distinct()
......
...@@ -11,7 +11,7 @@ using Stratis.Bitcoin.Utilities; ...@@ -11,7 +11,7 @@ using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
{ {
/// <summary> /// <summary>
/// CoinViewRule that prevents verifing ChangePointer input /// CoinViewRule that prevents verifing ChangePointer input
/// </summary> /// </summary>
public abstract class DeStreamCoinViewRule : CoinViewRule public abstract class DeStreamCoinViewRule : CoinViewRule
{ {
...@@ -94,9 +94,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -94,9 +94,11 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker); ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker);
if (verifyScriptResult == false) if (verifyScriptResult == false)
{
this.Logger.LogTrace( this.Logger.LogTrace(
"Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'", "Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'",
tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error); tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error);
}
return verifyScriptResult; return verifyScriptResult;
}); });
...@@ -123,8 +125,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -123,8 +125,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
} }
} }
else else
{
this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.",
index.Height); index.Height);
}
this.Logger.LogTrace("(-)"); this.Logger.LogTrace("(-)");
} }
...@@ -223,7 +227,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -223,7 +227,7 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
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 // 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;
...@@ -232,13 +236,16 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -232,13 +236,16 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
switch (context) switch (context)
{ {
case DeStreamPowRuleContext deStreamPowRuleContext: case DeStreamPowRuleContext deStreamPowRuleContext:
deStreamPowRuleContext.InputScriptPubKeys.AddRange(transaction.Inputs.RemoveChangePointer() deStreamPowRuleContext.InputScriptPubKeys.AddOrReplace(transaction.GetHash(), transaction.Inputs
.Select(p => view.GetOutputFor(p).ScriptPubKey)); .RemoveChangePointer()
.Select(p => view.GetOutputFor(p).ScriptPubKey).ToList());
deStreamPowRuleContext.TotalIn.Add(transaction.GetHash(), view.GetValueIn(transaction)); deStreamPowRuleContext.TotalIn.Add(transaction.GetHash(), view.GetValueIn(transaction));
break; break;
case DeStreamRuleContext deStreamPosRuleContext: case DeStreamRuleContext deStreamPosRuleContext:
deStreamPosRuleContext.InputScriptPubKeys.AddRange(transaction.Inputs.RemoveChangePointer() deStreamPosRuleContext.InputScriptPubKeys.AddOrReplace(transaction.GetHash(), transaction.Inputs
.Select(p => view.GetOutputFor(p).ScriptPubKey)); .RemoveChangePointer()
.Select(p => view.GetOutputFor(p).ScriptPubKey).ToList());
deStreamPosRuleContext.TotalIn.Add(transaction.GetHash(), view.GetValueIn(transaction)); deStreamPosRuleContext.TotalIn.Add(transaction.GetHash(), view.GetValueIn(transaction));
break; break;
default: default:
......
...@@ -25,10 +25,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -25,10 +25,10 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
switch (utxoRuleContext) switch (utxoRuleContext)
{ {
case DeStreamPowRuleContext deStreamPowRuleContext: case DeStreamPowRuleContext deStreamPowRuleContext:
deStreamPowRuleContext.InputScriptPubKeys = new List<Script>(); deStreamPowRuleContext.InputScriptPubKeys = new Dictionary<uint256, List<Script>>();
break; break;
case DeStreamRuleContext deStreamPosRuleContext: case DeStreamRuleContext deStreamPosRuleContext:
deStreamPosRuleContext.InputScriptPubKeys = new List<Script>(); deStreamPosRuleContext.InputScriptPubKeys = new Dictionary<uint256, List<Script>>();
break; break;
default: default:
throw new NotSupportedException( throw new NotSupportedException(
......
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