public IRpcMethodResult GetBaseTarget(long blockHeight) { try { var blockComponent = new BlockComponent(); BlockMsg lastBlock = null; BlockMsg prevStepBlock = null; if (blockHeight > 0) { lastBlock = blockComponent.GetBlockMsgByHeight(blockHeight - 1); prevStepBlock = blockComponent.GetBlockMsgByHeight(blockHeight - POC.DIFFIUCLTY_ADJUST_STEP); } long baseTarget; if (lastBlock != null) { baseTarget = POC.CalculateBaseTarget(blockHeight, lastBlock, prevStepBlock); } else { baseTarget = POC.CalculateBaseTarget(0, null, null); } return(Ok(baseTarget)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult GetDifficulty() { try { var blockComponent = new BlockComponent(); var height = blockComponent.GetLatestHeight(); var newHeight = height + 1; var previousBlockMsg = blockComponent.GetBlockMsgByHeight(height); var prevStepBlockMsg = blockComponent.GetBlockMsgByHeight(newHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1); var bits = POC.CalculateBaseTarget(height, previousBlockMsg, prevStepBlockMsg).ToString(); var result = new GetDifficultyOM() { height = newHeight, hashTarget = bits }; return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult GetBaseTarget(long blockHeight) { try { var blockComponent = new BlockComponent(); BlockMsg lastBlock = null; BlockMsg prevStepBlock = null; if (blockHeight > 0) { lastBlock = blockComponent.GetBlockMsgByHeight(blockHeight - 1); if (blockHeight >= POC.DIFFIUCLTY_ADJUST_STEP) { long prevStepHeight = 0; if (!GlobalParameters.IsTestnet && blockHeight <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = blockHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = blockHeight - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = blockComponent.GetBlockMsgByHeight(prevStepHeight); } } long baseTarget; if (lastBlock != null) { baseTarget = POC.CalculateBaseTarget(blockHeight, lastBlock, prevStepBlock); } else { baseTarget = POC.CalculateBaseTarget(0, null, null); } return(Ok(baseTarget)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult GetDifficulty() { try { var blockComponent = new BlockComponent(); var height = blockComponent.GetLatestHeight(); var newHeight = height + 1; var previousBlockEntity = blockComponent.GetBlockMsgByHeight(height); BlockMsg prevStepBlock = null; if (newHeight >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && newHeight <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = newHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = newHeight - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = blockComponent.GetBlockMsgByHeight(prevStepHeight); } var bits = POC.CalculateBaseTarget(height, previousBlockEntity, prevStepBlock).ToString(); var result = new GetDifficultyOM() { height = newHeight, hashTarget = bits }; return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
/// <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 = new AccountDac(); var blockDac = new BlockDac(); var outputDac = new OutputDac(); var txDac = new TransactionDac(); var txPool = TransactionPool.Instance; 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.Height; lastBlockHash = blockEntity.Hash; lastBlockBits = blockEntity.Bits; lastBlockGenerator = blockEntity.GeneratorId; } long totalSize = 0; long maxSize = BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); var poolItemList = txPool.MainPool.OrderByDescending(t => t.FeeRate).ToList(); var index = 0; while (totalSize < maxSize && index < poolItemList.Count) { var tx = poolItemList[index].Transaction; if (tx != null && transactionMsgs.Where(t => t.Hash == tx.Hash).Count() == 0) { if (txDac.SelectByHash(tx.Hash) == null) { transactionMsgs.Add(tx); totalSize += tx.Size; } else { txPool.RemoveTransaction(tx.Hash); } } else { break; } index++; } var minerAccount = accountDac.SelectDefaultAccount(); if (accountId != null) { var account = accountDac.SelectById(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 = BlockSetting.GenesisBlockReceiver; remark = BlockSetting.GenesisBlockRemark; } long totalAmount = 0; long totalFee = 0; foreach (var tx in transactionMsgs) { long totalInputsAmount = 0L; long totalOutputAmount = 0L; foreach (var input in tx.Inputs) { var utxo = outputDac.SelectByHashAndIndex(input.OutputTransactionHash, input.OutputIndex); if (utxo != null) { totalInputsAmount += utxo.Amount; } } foreach (var output in tx.Outputs) { totalOutputAmount += output.Amount; } totalAmount += totalOutputAmount; totalFee += (totalInputsAmount - totalOutputAmount); } //var work = new POW(headerMsg.Height); BlockMsg prevBlockMsg = null; BlockMsg prevStepBlockMsg = null; if (blockEntity != null) { prevBlockMsg = this.convertEntityToBlockMsg(blockEntity); } if (headerMsg.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { prevStepBlockMsg = this.GetBlockMsgByHeight(headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1); } 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; coinbaseTxMsg.Hash = coinbaseTxMsg.GetHash(); newBlockMsg.Transactions.Insert(0, coinbaseTxMsg); foreach (var tx in transactionMsgs) { newBlockMsg.Transactions.Add(tx); } headerMsg.PayloadHash = newBlockMsg.GetPayloadHash(); var dsa = ECDsa.ImportPrivateKey(Base16.Decode(minerAccount.PrivateKey)); var signResult = dsa.SingnData(Base16.Decode(headerMsg.PayloadHash)); headerMsg.BlockSignature = Base16.Encode(signResult); headerMsg.BlockSigSize = headerMsg.BlockSignature.Length; headerMsg.TotalTransaction = newBlockMsg.Transactions.Count; return(newBlockMsg); }
public bool VerifyBlock(BlockMsg newBlock) { if (this.exists(newBlock.Header.Hash)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HAS_BEEN_EXISTED); } if (newBlock.Header.Hash != newBlock.Header.GetHash()) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HASH_ERROR); } var blockComponent = new BlockComponent(); var previousBlock = this.GetBlockMsgByHash(newBlock.Header.PreviousBlockHash); if (newBlock.Header.Height > 0 && previousBlock == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.PREV_BLOCK_NOT_EXISTED); } if ((newBlock.Header.Timestamp > Time.EpochTime && (newBlock.Header.Timestamp - Time.EpochTime) > 2 * 60 * 60 * 1000) || (previousBlock != null && newBlock.Header.Timestamp <= previousBlock.Header.Timestamp)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_TIME_IS_ERROR); } if (newBlock.Serialize().Length > BlockSetting.MAX_BLOCK_SIZE) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIZE_LARGE_THAN_LIMIT); } var txComponent = new TransactionComponent(); var newBlockReward = POC.GetNewBlockReward(newBlock.Header.Height); var prevStepBlock = GetBlockMsgByHeight(newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1); var minerInfo = string.Empty; if (newBlock.Transactions.Count > 0) { var coinbase = newBlock.Transactions[0]; var totalFee = 0L; minerInfo = Encoding.UTF8.GetString(Base16.Decode(coinbase.Inputs[0].UnlockScript)).Split("`")[0]; if (newBlock.Transactions.Count > 1) { for (int i = 1; i < newBlock.Transactions.Count; i++) { long fee; if (txComponent.VerifyTransaction(newBlock.Transactions[i], out fee)) { totalFee += fee; } else { return(false); } } } if (coinbase.Inputs.Count != 1 || coinbase.Outputs.Count != 1 || coinbase.Inputs[0].OutputTransactionHash != Base16.Encode(HashHelper.EmptyHash())) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_FORMAT_ERROR); } else { var output = coinbase.Outputs[0]; if (output.Amount > BlockSetting.OUTPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT); } if (!Script.VerifyLockScriptFormat(output.LockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR); } if (output.Amount != (totalFee + newBlockReward)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } } } var pool = new MiningPoolComponent().GetMiningPoolByName(minerInfo); if (pool == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.MINING_POOL_NOT_EXISTED); } if (!POC.VerifyBlockSignature(newBlock.Header.PayloadHash, newBlock.Header.BlockSignature, pool.PublicKey)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIGNATURE_IS_ERROR); } long previousBlockHeight = -1; long previousBlockBits = -1; if (previousBlock != null) { previousBlockHeight = previousBlock.Header.Height; previousBlockBits = previousBlock.Header.Bits; } if (POC.CalculateBaseTarget(newBlock.Header.Height, previousBlock, prevStepBlock) != newBlock.Header.Bits) { throw new CommonException(ErrorCode.Engine.Block.Verify.BITS_IS_WRONG); } var targetResult = POC.CalculateTargetResult(newBlock); if (POC.Verify(newBlock.Header.Bits, targetResult)) { return(true); } else { throw new CommonException(ErrorCode.Engine.Block.Verify.POC_VERIFY_FAIL); } }
/// <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); }
public bool VerifyBlockBasic(BlockMsg newBlock) { if (newBlock.Header.Hash != newBlock.Header.GetHash()) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HASH_ERROR); } bool hasPreviousBlock = false; long previousBlockTimestamp = -1; long previousBlockBits = -1; long previousBlockHeight = newBlock.Header.Height - 1; var cacheBlockKey = $"{newBlock.Header.Hash}_{newBlock.Header.Height - 1}"; var previousBlockMsg = BlockDac.Default.SelectByHash(newBlock.Header.PreviousBlockHash); if (previousBlockMsg != null) { hasPreviousBlock = true; previousBlockTimestamp = previousBlockMsg.Header.Timestamp; previousBlockBits = previousBlockMsg.Header.Bits; } else { var previousBlock = BlockDac.Default.SelectByHash(newBlock.Header.PreviousBlockHash); hasPreviousBlock = previousBlock != null; if (hasPreviousBlock) { previousBlockTimestamp = previousBlock.Header.Timestamp; previousBlockBits = previousBlock.Header.Bits; } } if (newBlock.Header.Height > 0 && !hasPreviousBlock) { throw new CommonException(ErrorCode.Engine.Block.Verify.PREV_BLOCK_NOT_EXISTED); } if ((newBlock.Header.Timestamp - Time.EpochTime) > 2 * 60 * 60 * 1000 || (hasPreviousBlock && newBlock.Header.Timestamp <= previousBlockTimestamp)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_TIME_IS_ERROR); } if (newBlock.Serialize().Length > Consensus.BlockSetting.MAX_BLOCK_SIZE) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIZE_LARGE_THAN_LIMIT); } BlockMsg prevStepBlock = null; if (newBlock.Header.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && newBlock.Header.Height <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = BlockDac.Default.SelectByHeight(prevStepHeight); } //区块必须包含交易,否则错误 if (newBlock.Transactions == null || newBlock.Transactions.Count == 0) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.NOT_FOUND_COINBASE); } //第一个一定是coinbase,奖励+手续费 var coinbase = newBlock.Transactions[0]; //校验打包区块的矿池是否经过验证 var minerInfo = Encoding.UTF8.GetString(Base16.Decode(coinbase.Inputs[0].UnlockScript)).Split("`")[0]; var pool = MiningPoolComponent.CurrentMiningPools.FirstOrDefault(x => x.Name == minerInfo); if (pool == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.MINING_POOL_NOT_EXISTED); } //校验区块的签名信息 if (!POC.VerifyBlockSignature(newBlock.Header.PayloadHash, newBlock.Header.BlockSignature, pool.PublicKey)) { LogHelper.Warn($"PayloadHash::{newBlock.Header.PayloadHash}"); LogHelper.Warn($"BlockSignature::{newBlock.Header.BlockSignature}"); LogHelper.Warn($"PublicKey::{pool.PublicKey}"); throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIGNATURE_IS_ERROR); } if (POC.CalculateBaseTarget(newBlock.Header.Height, previousBlockBits, previousBlockTimestamp, prevStepBlock) != newBlock.Header.Bits) { throw new CommonException(ErrorCode.Engine.Block.Verify.BITS_IS_WRONG); } var targetResult = POC.CalculateTargetResult(newBlock); if (newBlock.Header.Height == 17687 || POC.Verify(newBlock.Header.Bits, targetResult)) { return(true); } else { throw new CommonException(ErrorCode.Engine.Block.Verify.POC_VERIFY_FAIL); } }