Commit 781d0b29 authored by Sergei Zubov's avatar Sergei Zubov

Modify fee calculations

Splitting fee between miner and DeStream extracted to function.
In consensus, sum of fees of all transactions is split, not each fee.
parent b2b99c47
...@@ -30,6 +30,18 @@ namespace NBitcoin ...@@ -30,6 +30,18 @@ namespace NBitcoin
/// </summary> /// </summary>
public double FeeRate { get; set; } public double FeeRate { get; set; }
/// <summary>
/// Splits fee between miner and DeStream
/// </summary>
/// <param name="fee">Total amount of fees to be split</param>
/// <param name="deStreamFee">DeStream fee part</param>
/// <param name="minerReward">Miner fee part</param>
public void SplitFee(long fee, out long deStreamFee, out long minerReward)
{
deStreamFee = Convert.ToInt64(fee * this.DeStreamFeePart);
minerReward = fee - deStreamFee;
}
public bool IsDeStreamAddress(string address) public bool IsDeStreamAddress(string address)
{ {
return this.DeStreamWallets.Contains(address); return this.DeStreamWallets.Contains(address);
......
...@@ -35,7 +35,9 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -35,7 +35,9 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
$"Rule context must be {nameof(DeStreamPowRuleContext)} or {nameof(DeStreamRuleContext)}"); $"Rule context must be {nameof(DeStreamPowRuleContext)} or {nameof(DeStreamRuleContext)}");
} }
if (Math.Abs(actualFee - expectedFee) > 1) this.Parent.Network.SplitFee(expectedFee, out long expectedDeStreamFee, out long _);
if (actualFee < expectedDeStreamFee)
ConsensusErrors.BadTransactionFeeOutOfRange.Throw(); ConsensusErrors.BadTransactionFeeOutOfRange.Throw();
return Task.CompletedTask; return Task.CompletedTask;
...@@ -67,13 +69,13 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules ...@@ -67,13 +69,13 @@ namespace Stratis.Bitcoin.Features.Consensus.Rules.CommonRules
private long GetFeeInTransaction(Transaction transaction, Money totalIn, private long GetFeeInTransaction(Transaction transaction, Money totalIn,
IEnumerable<Script> changeScriptPubKeys) IEnumerable<Script> changeScriptPubKeys)
{ {
double feeInTransaction = transaction.Outputs long feeInTransaction = Convert.ToInt64(transaction.Outputs
.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) > 1) if (Math.Abs(totalIn.Satoshi - transaction.TotalOut.Satoshi - feeInTransaction) > 1)
ConsensusErrors.BadTransactionFeeOutOfRange.Throw(); ConsensusErrors.BadTransactionFeeOutOfRange.Throw();
return (long) (feeInTransaction * this.Parent.Network.DeStreamFeePart); return feeInTransaction;
} }
} }
} }
\ No newline at end of file
...@@ -157,16 +157,6 @@ namespace Stratis.Bitcoin.Features.Miner ...@@ -157,16 +157,6 @@ namespace Stratis.Bitcoin.Features.Miner
this.logger.LogTrace("Worker #{0} found the kernel.", workersResult.KernelFoundIndex); this.logger.LogTrace("Worker #{0} found the kernel.", workersResult.KernelFoundIndex);
// Get reward for newly created block.
long reward = this.GetReward(fees, chainTip.Height);
if (reward < 0)
{
// TODO: This can't happen unless we remove reward for mined block.
// If this can happen over time then this check could be done much sooner
// to avoid a lot of computation.
this.logger.LogTrace("(-)[NO_REWARD]:false");
return false;
}
// Split stake if above threshold. // Split stake if above threshold.
this.SplitStake(nonEmptyUtxos, chainTip, coinstakeContext.CoinstakeTx.Outputs); this.SplitStake(nonEmptyUtxos, chainTip, coinstakeContext.CoinstakeTx.Outputs);
...@@ -174,11 +164,8 @@ namespace Stratis.Bitcoin.Features.Miner ...@@ -174,11 +164,8 @@ namespace Stratis.Bitcoin.Features.Miner
// Input to coinstake transaction. // Input to coinstake transaction.
UtxoStakeDescription coinstakeInput = workersResult.KernelCoin; UtxoStakeDescription coinstakeInput = workersResult.KernelCoin;
// Total amount of input values in coinstake transaction.
long coinstakeInputValue = coinstakeInput.TxOut.Value + reward;
// Set output amount. // Set output amount.
this.SetOutputAmount(coinstakeContext.CoinstakeTx.Outputs, coinstakeInput.TxOut.Value, fees, reward); this.SetOutputAmount(coinstakeContext.CoinstakeTx.Outputs, coinstakeInput.TxOut.Value, fees);
// Sign. // Sign.
if (!this.SignTransactionInput(coinstakeInput, coinstakeContext.CoinstakeTx)) if (!this.SignTransactionInput(coinstakeInput, coinstakeContext.CoinstakeTx))
...@@ -204,32 +191,27 @@ namespace Stratis.Bitcoin.Features.Miner ...@@ -204,32 +191,27 @@ namespace Stratis.Bitcoin.Features.Miner
return true; return true;
} }
private void SetOutputAmount(TxOutList outputs, long totalOut, long fees, long reward) private void SetOutputAmount(TxOutList outputs, long totalOut, long fees)
{ {
this.network.SplitFee(fees, out long deStreamFee, out long minerReward);
if (outputs.Count == 4) if (outputs.Count == 4)
{ {
outputs[1].Value = (totalOut + reward) / 2 / Money.CENT * Money.CENT; outputs[1].Value = (totalOut + minerReward) / 2 / Money.CENT * Money.CENT;
outputs[2].Value = totalOut + reward - outputs[1].Value; outputs[2].Value = totalOut + minerReward - outputs[1].Value;
outputs[3].Value = fees - reward; outputs[3].Value = deStreamFee;
this.logger.LogTrace("Coinstake first output value is {0}, second is {1}, third is {3}.", this.logger.LogTrace("Coinstake first output value is {0}, second is {1}, third is {3}.",
outputs[1].Value, outputs[2].Value, outputs[3].Value); outputs[1].Value, outputs[2].Value, outputs[3].Value);
} }
else else
{ {
outputs[1].Value = totalOut + reward; outputs[1].Value = totalOut + minerReward;
outputs[2].Value = fees - reward; outputs[2].Value = deStreamFee;
this.logger.LogTrace("Coinstake first output value is {0}, second is {1} .", outputs[1].Value, this.logger.LogTrace("Coinstake first output value is {0}, second is {1} .", outputs[1].Value,
outputs[2].Value); outputs[2].Value);
} }
} }
private long GetReward(long fees, int chainTipHeight)
{
return (long) (fees * (1 - this.network.DeStreamFeePart)) +
this.consensusLoop.ConsensusRules.GetRule<PosCoinviewRule>()
.GetProofOfStakeReward(chainTipHeight + 1);
}
private void SplitStake(int nonEmptyUtxos, ChainedHeader chainTip, TxOutList outputs) private void SplitStake(int nonEmptyUtxos, ChainedHeader chainTip, TxOutList outputs)
{ {
if (!this.GetSplitStake(nonEmptyUtxos, chainTip)) return; if (!this.GetSplitStake(nonEmptyUtxos, chainTip)) return;
......
using System.Linq; using System;
using System.Linq;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
...@@ -63,9 +64,9 @@ namespace Stratis.Bitcoin.Features.Miner ...@@ -63,9 +64,9 @@ namespace Stratis.Bitcoin.Features.Miner
// pblocktemplate->CoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); // pblocktemplate->CoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
var coinviewRule = this.ConsensusLoop.ConsensusRules.GetRule<CoinViewRule>(); var coinviewRule = this.ConsensusLoop.ConsensusRules.GetRule<CoinViewRule>();
this.coinbase.Outputs[0].Value = (long) (this.fees.Satoshi * (1 - this.Network.DeStreamFeePart)) + this.Network.SplitFee(this.fees.Satoshi, out long deStreamFee, out long minerReward);
coinviewRule.GetProofOfWorkReward(this.height); this.coinbase.Outputs[0].Value = minerReward;
this.coinbase.Outputs[1].Value = (long) (this.fees.Satoshi * this.Network.DeStreamFeePart); this.coinbase.Outputs[1].Value = deStreamFee;
this.BlockTemplate.TotalFee = this.fees; this.BlockTemplate.TotalFee = this.fees;
int nSerializeSize = this.block.GetSerializedSize(); int nSerializeSize = this.block.GetSerializedSize();
......
using System.Linq; using System;
using System.Linq;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
...@@ -63,9 +64,9 @@ namespace Stratis.Bitcoin.Features.Miner ...@@ -63,9 +64,9 @@ namespace Stratis.Bitcoin.Features.Miner
// pblocktemplate->CoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); // pblocktemplate->CoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
var coinviewRule = this.ConsensusLoop.ConsensusRules.GetRule<CoinViewRule>(); var coinviewRule = this.ConsensusLoop.ConsensusRules.GetRule<CoinViewRule>();
this.coinbase.Outputs[0].Value = (long) (this.fees.Satoshi * (1 - this.Network.DeStreamFeePart)) + this.Network.SplitFee(this.fees.Satoshi, out long deStreamFee, out long minerReward);
coinviewRule.GetProofOfWorkReward(this.height); this.coinbase.Outputs[0].Value = minerReward;
this.coinbase.Outputs[1].Value = (long) (this.fees.Satoshi * this.Network.DeStreamFeePart); this.coinbase.Outputs[1].Value = deStreamFee;
this.BlockTemplate.TotalFee = this.fees; this.BlockTemplate.TotalFee = this.fees;
int nSerializeSize = this.block.GetSerializedSize(); int nSerializeSize = this.block.GetSerializedSize();
......
...@@ -22,7 +22,7 @@ namespace Stratis.Bitcoin.Features.Wallet ...@@ -22,7 +22,7 @@ namespace Stratis.Bitcoin.Features.Wallet
/// <inheritdoc /> /// <inheritdoc />
protected override void AddFee(TransactionBuildContext context) protected override void AddFee(TransactionBuildContext context)
{ {
long fee = (long) (context.Recipients.Sum(p => p.Amount) * this.Network.FeeRate); long fee = Convert.ToInt64(context.Recipients.Sum(p => p.Amount) * this.Network.FeeRate);
context.TransactionFee = fee; context.TransactionFee = fee;
context.TransactionBuilder.SendFees(fee); context.TransactionBuilder.SendFees(fee);
} }
......
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