private void BeforeSave(CurrencyBlock block)
 {
     foreach (var transaction in block.Transactions)
     {
         transaction.Hash = HashProvider.ComputeHashBytes(transaction);
     }
     block.Hash = block.ToHashBytes(HashProvider);
 }
示例#2
0
        public bool CheckBlock(CurrencyBlock newBlock, CurrencyBlock previousBlock)
        {
            var blockHash = newBlock.ToHashBytes(_hashProvider);

            if (previousBlock.Index + 1 != newBlock.Index)
            { // Check if the block is the last one
                var message = $"Invalid index: expected '{previousBlock.Index + 1}' but got '{newBlock.Index}'";
                _logger?.LogError(message);
                throw new BlockAssertionException(message);
            }
            if (previousBlock.Hash != newBlock.PreviousHash)
            {     // Check if the previous block is correct
                var message = $"Invalid previoushash: expected '{previousBlock.Hash}' got '{newBlock.PreviousHash}'";
                _logger?.LogError(message);
                throw new BlockAssertionException(message);
            }
            if (blockHash != newBlock.Hash)
            {     // Check if the hash is correct
                var message = $"Invalid hash: expected '{blockHash}' got '{newBlock.Hash}'";
                throw new BlockAssertionException(message);
            }
            if (newBlock.GetDifficulty() >= GetDifficulty(newBlock.Index ?? 0))
            {             // If the difficulty level of the proof-of-work challenge is correct
                var message = $"Invalid proof-of-work difficulty: expected '{newBlock.GetDifficulty()}' to be smaller than '{GetDifficulty(newBlock.Index ?? 0)}'";
                _logger?.LogError(message);
                throw new BlockAssertionException(message);
            }

            // For each transaction in this block, check if it is valid
            foreach (var transaction in newBlock.Transactions)
            {
                CheckTransaction(transaction);
            }

            // Check if the sum of output transactions are equal the sum of input transactions + the reward for the block miner
            {
                var sumOfInputsAmount  = newBlock.Transactions.SelectMany(x => x.Data.Inputs).Select(x => x.Amount).Sum();
                var sumOfOutputsAmount = newBlock.Transactions.SelectMany(x => x.Data.Outputs).Select(x => x.Amount).Sum();

                if (sumOfInputsAmount < sumOfOutputsAmount)
                {
                    var message = $"Invalid block balance: inputs sum '{sumOfInputsAmount}', outputs sum '{sumOfOutputsAmount}'";
                    _logger?.LogError(message);
                    throw new BlockAssertionException(message);
                }
            }

            // Check if there is only 1 fee transaction and 1 reward transaction
            {
                var feeTransactions = newBlock.Transactions.Count(x => x.Type == TransactionType.Fee);
                if (feeTransactions > 1)
                {
                    var message = $"Invalid fee transaction count: expected '1' got '${feeTransactions}'";
                    _logger?.LogError(message);
                    throw new BlockAssertionException(message);
                }
                var rewardTransactions = newBlock.Transactions.Count(x => x.Type == TransactionType.Reward);
                if (rewardTransactions > 1)
                {
                    var message = $"Invalid reward transaction count: expected '1' got '${rewardTransactions}'";
                    _logger?.LogError(message);
                    throw new BlockAssertionException(message);
                }
            }

            return(true);
        }