public void PostValidateBlock(Chain newChain, object finalTally)
{
var chainedHeader = newChain.LastBlock;
var blockTally = (BlockTally)finalTally;
// ensure there is at least 1 transaction
if (blockTally.TxCount == 0)
throw new ValidationException(chainedHeader.Hash,
$"Failing block {chainedHeader.Hash} at height {chainedHeader.Height}: Zero transactions present");
// ensure fees aren't negative (should be caught earlier)
if (blockTally.TotalFees < 0)
throw new ValidationException(chainedHeader.Hash);
// calculate the expected reward in coinbase
var subsidy = (ulong)(50 * SATOSHI_PER_BTC);
if (chainedHeader.Height / 210000 <= 32)
subsidy /= (ulong)Math.Pow(2, chainedHeader.Height / 210000);
// calculate the expected reward in coinbase
var expectedReward = subsidy + (ulong)blockTally.TotalFees;
// calculate the actual reward in coinbase
var actualReward = blockTally.CoinbaseTx.Transaction.Outputs.Sum(x => x.Value);
// ensure coinbase has correct reward
if (actualReward > expectedReward)
{
throw new ValidationException(chainedHeader.Hash,
$"Failing block {chainedHeader.Hash} at height {chainedHeader.Height}: Coinbase value is greater than reward + fees");
}
}