Example #1
0
        /// <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);
        }
Example #2
0
        public static void ForgeBlock(ForgeMsg msg)
        {
            try
            {
                LogHelper.Info("Forge Block 3");

                LogHelper.Info($"msg == null : {msg == null} ; PoolCenterJob.Current == null : {PoolCenterJob.Current == null}");
                var startMsg = PoolCenterJob.Current.CurrentStartMiningMsg;

                if (msg != null && PoolCenterJob.Current != null && startMsg != null)
                {
                    LogHelper.Info($"{startMsg.Id},{msg.StartMsgId}");
                }
                if (msg == null || PoolCenterJob.Current == null || startMsg == null || startMsg.Id != msg.StartMsgId)
                {
                    return;
                }
                LogHelper.Info("Forge Block 4");

                var blockMsg = RedisManager.Current.GetDataInRedis <BlockMsg>(msg.StartMsgId);
                if (blockMsg == null || blockMsg.Header.Height < startMsg.BlockHeight)
                {
                    return;
                }

                LogHelper.Info("Forge Block 5");
                if (!(blockMsg.Header.Height > NodeApi.Current.GetBlockHeight()))
                {
                    return;
                }

                LogHelper.Info("Forge Block 6");
                LogHelper.Info("Received Msg [ForgeBlock]");
                BlockMsg successBlock = null;
                if (PoolCenterJob.Current.ForgeBlock(msg.StartMsgId, msg.Account, msg.Nonce, out successBlock))
                {
                    CenterCache.GenarateBlockCount++;
                    PoolCenterJob.Current.StopMining(true, msg.StartMsgId);

                    //分析存币交易
                    ProcessDepositTx(successBlock);
                    Task.Delay(Setting.MaxMiningBlockCount).Wait();
                    PoolCenterJob.Current.Start();

                    Task.Run(() =>
                    {
                        if (PoolCenterJob.Current.RemoveStartMsgIds.ContainsKey(msg.StartMsgId))
                        {
                            PoolCenterJob.Current.RemoveStartMsgIds[msg.StartMsgId] = Time.EpochTime;
                        }
                        Task.Delay(Setting.SAVE_REWARDS_BEHIND_GENERATETIME_BLOCK).Wait();
                        var height = Convert.ToInt32(blockMsg.Header.Height);
                        PoolApi.SaveRewards(msg.StartMsgId, msg.Nonce, height);
                    });
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.ToString());
            }
        }
Example #3
0
        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);
            }
        }