public bool VerifyBlock(BlockMsg newBlock) { //校验区块的基本信息 var result = VerifyBlockBasic(newBlock); if (!result) { return(false); } var txComponent = new TransactionComponent(); var blockComponent = new BlockComponent(); //校验交易信息 var totalFee = 0L; VerifyTransactionModel model = new VerifyTransactionModel(); model.block = newBlock; model.localHeight = blockComponent.GetLatestHeight(); foreach (var item in newBlock.Transactions) { long fee; model.transaction = item; if (txComponent.VerifyTransactionMsg(model, out fee)) { totalFee += fee; } else { return(false); } } if (Heights.Contains(newBlock.Header.Height)) { return(true); } var newBlockReward = POC.GetNewBlockReward(newBlock.Header.Height); var coinbaseAmount = newBlock.Transactions[0].Outputs[0].Amount; if (coinbaseAmount < 0 || coinbaseAmount != (totalFee + newBlockReward)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } return(true); }
/// <summary> /// 创建新的区块 /// </summary> /// <param name="minerName"></param> /// <param name="generatorId"></param> /// <param name="accountId"></param> /// <returns></returns> public BlockMsg CreateNewBlock(string minerName, string generatorId, string remark = null, string accountId = null) { var accountDac = AccountDac.Default; var blockDac = BlockDac.Default; var txDac = TransactionDac.Default; var txPool = TransactionPool.Instance; var txComponent = new TransactionComponent(); var transactionMsgs = new List <TransactionMsg>(); long lastBlockHeight = -1; string lastBlockHash = Base16.Encode(HashHelper.EmptyHash()); long lastBlockBits = -1; string lastBlockGenerator = null; //获取最后一个区块 var blockEntity = blockDac.SelectLast(); if (blockEntity != null) { lastBlockHeight = blockEntity.Header.Height; lastBlockHash = blockEntity.Header.Hash; lastBlockBits = blockEntity.Header.Bits; lastBlockGenerator = blockEntity.Header.GeneratorId; } long totalSize = 0; long totalInput = 0; long totalOutput = 0; long totalAmount = 0; long totalFee = 0; long maxSize = Consensus.BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); //获取待打包的交易 var txs = txPool.GetTxsWithoutRepeatCost(10, maxSize); var hashIndexs = new List <string>(); foreach (var tx in txs) { totalSize += tx.Size; totalInput += tx.InputCount; totalOutput += tx.OutputCount; hashIndexs.AddRange(tx.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}")); long totalOutputAmount = tx.Outputs.Sum(x => x.Amount); totalAmount += totalOutputAmount; } var utxos = UtxoSetDac.Default.Get(hashIndexs); var totalInputAmount = utxos.Sum(x => x.Amount); totalFee = totalInputAmount - totalAmount; transactionMsgs.AddRange(txs); var accounts = AccountDac.Default.SelectAll(); var minerAccount = accounts.OrderBy(x => x.Timestamp).FirstOrDefault(); if (accountId != null) { var account = accounts.FirstOrDefault(x => x.Id == accountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { minerAccount = account; } } var minerAccountId = minerAccount.Id; BlockMsg newBlockMsg = new BlockMsg(); BlockHeaderMsg headerMsg = new BlockHeaderMsg(); headerMsg.Hash = Base16.Encode(HashHelper.EmptyHash()); headerMsg.GeneratorId = generatorId; newBlockMsg.Header = headerMsg; headerMsg.Height = lastBlockHeight + 1; headerMsg.PreviousBlockHash = lastBlockHash; if (headerMsg.Height == 0) { minerAccountId = Consensus.BlockSetting.GenesisBlockReceiver; remark = Consensus.BlockSetting.GenesisBlockRemark; } BlockMsg prevBlockMsg = null; BlockMsg prevStepBlockMsg = null; if (blockEntity != null) { prevBlockMsg = blockEntity; } if (headerMsg.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && headerMsg.Height <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlockMsg = blockDac.SelectByHeight(prevStepHeight); } var newBlockReward = POC.GetNewBlockReward(headerMsg.Height); headerMsg.Bits = POC.CalculateBaseTarget(headerMsg.Height, prevBlockMsg, prevStepBlockMsg); headerMsg.TotalTransaction = transactionMsgs.Count + 1; var coinbaseTxMsg = new TransactionMsg(); coinbaseTxMsg.Timestamp = Time.EpochTime; coinbaseTxMsg.Locktime = 0; var coinbaseInputMsg = new InputMsg(); coinbaseTxMsg.Inputs.Add(coinbaseInputMsg); coinbaseInputMsg.OutputIndex = 0; coinbaseInputMsg.OutputTransactionHash = Base16.Encode(HashHelper.EmptyHash()); coinbaseInputMsg.UnlockScript = Script.BuildMinerScript(minerName, remark); coinbaseInputMsg.Size = coinbaseInputMsg.UnlockScript.Length; var coinbaseOutputMsg = new OutputMsg(); coinbaseTxMsg.Outputs.Add(coinbaseOutputMsg); coinbaseOutputMsg.Amount = newBlockReward + totalFee; coinbaseOutputMsg.LockScript = Script.BuildLockScipt(minerAccountId); coinbaseOutputMsg.Size = coinbaseOutputMsg.LockScript.Length; coinbaseOutputMsg.Index = 0; if (newBlockReward < 0 || totalFee < 0 || coinbaseOutputMsg.Amount < 0) { LogHelper.Warn($"newBlockReward:{newBlockReward}"); LogHelper.Warn($"totalFee:{totalFee}"); LogHelper.Warn($"coinbaseOutputMsg.Amount:{coinbaseOutputMsg.Amount}"); throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } coinbaseTxMsg.Hash = coinbaseTxMsg.GetHash(); newBlockMsg.Transactions.Insert(0, coinbaseTxMsg); foreach (var tx in transactionMsgs) { newBlockMsg.Transactions.Add(tx); } headerMsg.PayloadHash = newBlockMsg.GetPayloadHash(); LogHelper.Warn($"{headerMsg.Height}::{headerMsg.PayloadHash}"); LogHelper.Warn($"PayloadHash::{headerMsg.PayloadHash}"); LogHelper.Warn($"BlockSignature::{headerMsg.BlockSignature}"); LogHelper.Warn($"miner::{minerName}"); headerMsg.BlockSignature = Base16.Encode(HashHelper.EmptyHash()); headerMsg.BlockSigSize = headerMsg.BlockSignature.Length; headerMsg.TotalTransaction = newBlockMsg.Transactions.Count; return(newBlockMsg); }