public async Task <bool> CheckChainAsync(IReadOnlyList <Block> blockchainToValidate) { // Check if the genesis block is the same if (_hashProvider.ComputeHashString(blockchainToValidate[0]) != _hashProvider.ComputeHashString(await _blocks.GetGenesisBlockAsync())) { var message = $"Genesis blocks aren't the same"; _logger?.LogError(message); throw new BlockchainAssertionException(message); } // Compare every block to the previous one (it skips the first one, because it was verified before) try { for (var i = 1; i < blockchainToValidate.Count; i++) { CheckBlock(blockchainToValidate[i], blockchainToValidate[i - 1]); } } catch (Exception ex) { var message = $"Invalid block sequence"; _logger?.LogError(message); throw new BlockchainAssertionException(message, ex); } return(true); }
public Transaction Build() { // Check required information if (_utxo == null) { throw new ArgumentException($"It's necessary to provide a list of unspent output transactions."); } if (_outputAddress == null) { throw new ArgumentException($"It's necessary to provide the destination address."); } if (_totalAmount == null) { throw new ArgumentException($"It's necessary to provide the transaction value."); } // Calculates the change amount var changeAmount = _utxo.Sum(x => x.Amount) - _totalAmount - _feeAmount; var transactionId = CryptoUtil.RandomString(); // For each transaction input, calculates the hash of the input and signs the data var inputIndex = 1; var inputs = _utxo.Select(utxo => { var keyPair = Ed25519.GenerateKeyPairFromSecret(_secretKey); var hash = _hashProvider.ComputeHashString(new { Transaction = utxo.TransactionId, utxo.Index, utxo.Address }); utxo.Signature = Ed25519.Sign(keyPair, hash); return(utxo); }).Select(x => new TransactionItem { TransactionId = x.TransactionId, Index = x.Index, Address = x.Address, Amount = x.Amount, Signature = x.Signature, Type = TransactionDataType.Input }).AsList(); // Add target receiver var outputIndex = 1; var outputs = new List <TransactionItem> { new TransactionItem { Index = outputIndex++, TransactionId = transactionId, Amount = _totalAmount.Value, Address = _outputAddress, Type = TransactionDataType.Output } }; // Add change amount if (changeAmount > 0) { outputs.Add(new TransactionItem { Index = outputIndex, TransactionId = transactionId, Amount = changeAmount.GetValueOrDefault(), Address = _changeAddress, Type = TransactionDataType.Output }); } // The remaining value is the fee to be collected by the block's creator var transaction = new Transaction { Id = transactionId, Type = _type, Data = new TransactionData { Inputs = inputs, Outputs = outputs.AsList() } }; transaction.Hash = _hashProvider.ComputeHashBytes(transaction); return(transaction); }
public static string ToHashString(this Block block, IHashProvider hashProvider) { return(hashProvider.ComputeHashString(block)); }
public string ToHashString(IHashProvider provider) { return(provider.ComputeHashString(this)); }