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()
......
...@@ -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("(-)");
} }
...@@ -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