Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        public bool VerifyTransactionMsg(VerifyTransactionModel model, out long fee)
        {
            var transaction = model.transaction;

            //校验锁定时间
            if (transaction.Locktime > 0 && transaction.ExpiredTime == transaction.Locktime)
            {
                transaction.ExpiredTime = 0;
            }

            //校验HASH值
            if (transaction.Hash != transaction.GetHash())
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_HASH_ERROR);
            }

            //交易必须包含输入和输出
            if (transaction.InputCount == 0 || transaction.OutputCount == 0)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_AND_OUTPUT_CANNOT_BE_EMPTY);
            }

            //校验交易的时间
            if (transaction.Locktime < 0 || transaction.Locktime > (Time.EpochTime + BlockSetting.LOCK_TIME_MAX))
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.LOCK_TIME_EXCEEDED_THE_LIMIT);
            }

            //校验交易量
            if (transaction.Serialize().Length < BlockSetting.TRANSACTION_MIN_SIZE)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_SIZE_BELOW_THE_LIMIT);
            }

            return(VerifyTransactionData(model, out fee));
        }
Exemplo n.º 3
0
        public bool VerifyTransactionData(VerifyTransactionModel model, out long fee)
        {
            long totalOutput = 0;
            long totalInput  = 0;

            var transaction = model.transaction;
            var block       = model.block;
            var localHeight = model.localHeight;

            List <Output> outputEntities = new List <Output>();
            List <Input>  inputEntities  = new List <Input>();

            #region 校验和转换 接收地址
            foreach (var output in transaction.Outputs)
            {
                if ((output.Amount <= 0 || output.Amount > BlockSetting.OUTPUT_AMOUNT_MAX) && !Heights.Contains(block.Header.Height))
                {
                    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);
                }

                var outputEntity = output.ConvertToEntiry(transaction, block);
                outputEntities.Add(outputEntity);

                totalOutput += output.Amount;
            }
            #endregion

            #region 判断是不是在一个区块内重复花费(24696之前有错误数据)
            if (block.Header.Height <= 24696)
            {
                var inputsCount = transaction.Inputs.Select(x => x.OutputTransactionHash + x.OutputIndex).Distinct().Count();
                if (inputsCount < transaction.Inputs.Count)
                {
                    throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_NOT_EXISTED);
                }
            }
            #endregion


            var  firstInput = transaction.Inputs[0];
            bool isCoinbase = firstInput.OutputTransactionHash == COINBASE_INPUT_HASH;
            if (isCoinbase)
            {
                #region 如果是Coinbase
                var inputps = new InputExtensionParams();
                inputps.BlockHash       = block.Header.Hash;
                inputps.InputAccountId  = null;
                inputps.InputAmount     = 0;
                inputps.TransactionHash = transaction.Hash;
                var inputEntity = firstInput.ConvertToEntiry(inputps);

                totalInput += 0;
                inputEntities.Add(inputEntity);
                isCoinbase = true;
                #endregion
            }
            else
            {
                foreach (var input in transaction.Inputs)
                {
                    if (!Script.VerifyUnlockScriptFormat(input.UnlockScript))
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR);
                    }

                    var output = UtxoSetDac.Default.Get(input.OutputTransactionHash, input.OutputIndex);
                    if (output == null)
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_NOT_EXISTED);
                    }

                    //是否已经上链了(存在重复写入的情况)
                    if (output.IsSpent() && output.SpentHeight != block.Header.Height && block.Header.Height > 24696)
                    {
                        LogHelper.Warn($"transaction.Hash:{transaction.Hash}");
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_HAS_BEEN_SPENT);
                    }

                    long blockHeight = output.BlockHeight;
                    //判断挖矿的区块等待100个确认
                    if (output.IsCoinbase && !output.IsConfirmed(block.Header.Height))
                    {
                        if (output.IsCoinbase)
                        {
                            throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_NEED_100_CONFIRMS);
                        }
                        else
                        {
                            throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_NEED_6_CONFIRMS);
                        }
                    }
                    //判断余额是否已经解锁
                    if (Time.EpochTime < output.Locktime)
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_IS_LOCKED);
                    }

                    //校验存币时间,当前时间大于存币过期时间才能使用
                    if (output.DepositTime > 0 && output.DepositTime >= Time.EpochTime)
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.DEPOSIT_TIME_NOT_EXPIRED);
                    }

                    string lockScript = output.LockScript;

                    if (!Script.VerifyLockScriptByUnlockScript(input.OutputTransactionHash, input.OutputIndex, lockScript, input.UnlockScript))
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_UNLOCK_FAIL);
                    }
                    var inputps = new InputExtensionParams();
                    inputps.BlockHash       = block.Header.Hash;
                    inputps.InputAccountId  = output.Account;
                    inputps.InputAmount     = output.Amount;
                    inputps.TransactionHash = transaction.Hash;
                    var inputEntity = input.ConvertToEntiry(inputps);

                    totalInput += output.Amount;

                    inputEntities.Add(inputEntity);
                }

                if (totalOutput >= totalInput)
                {
                    throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_LARGE_THAN_INPUT);
                }

                if ((totalInput - totalOutput) < BlockSetting.TRANSACTION_MIN_FEE)
                {
                    throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_FEE_IS_TOO_FEW);
                }
            }

            if (totalInput > BlockSetting.INPUT_AMOUNT_MAX)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_EXCEEDED_THE_LIMIT);
            }

            if (totalOutput > BlockSetting.OUTPUT_AMOUNT_MAX)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT);
            }

            if (isCoinbase)
            {
                fee = 0;
            }
            else
            {
                fee = totalInput - totalOutput;
            }
            return(true);
        }