Пример #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);
        }
Пример #2
0
        public GetTxOutSetInfoOM GetTxOutSetInfo()
        {
            GetTxOutSetInfoOM result = new GetTxOutSetInfoOM();
            var blockComponent       = new BlockComponent();

            result.height    = GlobalParameters.LocalHeight;
            result.bestblock = BlockDac.Default.GetBlockHashByHeight(result.height);
            var       accounts  = AccountDac.Default.GetMyAccountBook();
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            var confirmedUtxos = UtxoSetDac.Default.GetMyUnspentUtxoKeys().ToArray();

            stopwatch.Stop();
            LogHelper.Warn($"[accounts Count] :: {accounts.Count}");
            LogHelper.Warn($"[GetMyUnspentUtxoKeys] use time :: {stopwatch.ElapsedMilliseconds}");
            var transacionCount = confirmedUtxos.Select(x => x.Split("_")[0]).Distinct().Count();

            result.transactions = transacionCount;
            result.txouts       = confirmedUtxos.Count();
            result.total_amount = UtxoSetDac.Default.GetConfirmedAmount() - TransactionPoolDac.Default.UseBalanceInPool;
            return(result);
        }
Пример #3
0
        public bool VerifyTransaction(TransactionMsg transaction, out long txFee, out long totalOutput, out long totalInput)
        {
            var blockComponent = new BlockComponent();

            txFee = 0;
            //compatible with old node
            if (transaction.Locktime > 0 && transaction.ExpiredTime == transaction.Locktime)
            {
                transaction.ExpiredTime = 0;
            }

            //step 0
            if (transaction.Hash != transaction.GetHash())
            {
                LogHelper.Error("Tx Hash Error:" + transaction.Hash);
                LogHelper.Error("Timestamp:" + transaction.Timestamp);
                LogHelper.Error("Locktime:" + transaction.Locktime);
                LogHelper.Error("ExpiredTime:" + transaction.ExpiredTime);
                LogHelper.Error("InputCount:" + transaction.InputCount);
                LogHelper.Error("OutputCount:" + transaction.OutputCount);

                throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_HASH_ERROR);
            }

            //step 1
            if (transaction.InputCount == 0 || transaction.OutputCount == 0)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.INPUT_AND_OUTPUT_CANNOT_BE_EMPTY);
            }

            //step 2
            if (transaction.Hash == Base16.Encode(HashHelper.EmptyHash()))
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.HASH_CANNOT_BE_EMPTY);
            }

            //step 3
            if (transaction.Locktime < 0 || transaction.Locktime > (Time.EpochTime + BlockSetting.LOCK_TIME_MAX))
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.LOCK_TIME_EXCEEDED_THE_LIMIT);
            }

            //step 4
            if (transaction.Serialize().Length < BlockSetting.TRANSACTION_MIN_SIZE)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_SIZE_BELOW_THE_LIMIT);
            }

            //step 5
            if (this.existsInDB(transaction.Hash))
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_HAS_BEEN_EXISTED);
            }

            totalOutput = 0;
            totalInput  = 0;

            foreach (var output in transaction.Outputs)
            {
                if (output.Amount <= 0 || 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);
                }

                totalOutput += output.Amount;
            }

            var count = transaction.Inputs.Distinct().Count();

            if (count != transaction.Inputs.Count)
            {
                throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_DUPLICATED_IN_ONE_TRANSACTION);
            }

            foreach (var input in transaction.Inputs)
            {
                if (!Script.VerifyUnlockScriptFormat(input.UnlockScript))
                {
                    throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR);
                }

                var utxo = UtxoSetDac.Default.Get(input.OutputTransactionHash, input.OutputIndex);
                if (utxo != null)
                {
                    if (!utxo.IsConfirmed(GlobalParameters.LocalHeight))
                    {
                        if (utxo.IsCoinbase)
                        {
                            throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_NEED_100_CONFIRMS);
                        }
                        else
                        {
                            return(false);
                        }
                    }

                    if (Time.EpochTime < utxo.Locktime)
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.TRANSACTION_IS_LOCKED);
                    }

                    if (utxo.IsSpent())
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_HAS_BEEN_SPENT);
                    }

                    if (!Script.VerifyLockScriptByUnlockScript(input.OutputTransactionHash, input.OutputIndex, utxo.LockScript, input.UnlockScript))
                    {
                        throw new CommonException(ErrorCode.Engine.Transaction.Verify.UTXO_UNLOCK_FAIL);
                    }

                    totalInput += utxo.Amount;
                }
                else
                {
                    //not found output, wait for other transactions or blocks;
                    txFee = 0;
                    return(false);
                }
            }

            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);
            }

            txFee = totalInput - totalOutput;
            return(true);
        }