예제 #1
0
        private BlockMsg convertEntityToBlockMsg(Block entity)
        {
            var txDac     = new TransactionDac();
            var inputDac  = new InputDac();
            var outputDac = new OutputDac();

            var blockMsg  = new BlockMsg();
            var headerMsg = new BlockHeaderMsg();

            headerMsg.Version           = entity.Version;
            headerMsg.Hash              = entity.Hash;
            headerMsg.Height            = entity.Height;
            headerMsg.PreviousBlockHash = entity.PreviousBlockHash;
            headerMsg.Bits              = entity.Bits;
            headerMsg.Nonce             = entity.Nonce;
            headerMsg.Timestamp         = entity.Timestamp;

            var transactions = txDac.SelectByBlockHash(entity.Hash);

            headerMsg.TotalTransaction = transactions == null ? 0: transactions.Count;

            foreach (var tx in transactions)
            {
                var txMsg = new TransactionMsg();
                txMsg.Version   = tx.Version;
                txMsg.Hash      = tx.Hash;
                txMsg.Timestamp = tx.Timestamp;
                txMsg.Locktime  = tx.LockTime;

                var inputs  = inputDac.SelectByTransactionHash(tx.Hash);
                var outputs = outputDac.SelectByTransactionHash(tx.Hash);

                foreach (var input in inputs)
                {
                    txMsg.Inputs.Add(new InputMsg
                    {
                        OutputTransactionHash = input.OutputTransactionHash,
                        OutputIndex           = input.OutputIndex,
                        Size         = input.Size,
                        UnlockScript = input.UnlockScript
                    });
                }

                foreach (var output in outputs)
                {
                    txMsg.Outputs.Add(new OutputMsg
                    {
                        Index      = output.Index,
                        Amount     = output.Amount,
                        Size       = output.Size,
                        LockScript = output.LockScript
                    });
                }

                blockMsg.Transactions.Add(txMsg);
            }

            blockMsg.Header = headerMsg;
            return(blockMsg);
        }
예제 #2
0
        //Check whether output has been spent or contained in another transaction, true = spent, false = unspent
        private bool checkOutputSpent(string currentTxHash, string outputTxHash, int outputIndex)
        {
            var outputDac = new OutputDac();
            var inputDac  = new InputDac();
            var txDac     = new TransactionDac();
            var blockDac  = new BlockDac();

            var outputEntity = outputDac.SelectByHashAndIndex(outputTxHash, outputIndex);
            var inputEntity  = inputDac.SelectByOutputHash(outputTxHash, outputIndex);

            if (inputEntity != null && inputEntity.TransactionHash != currentTxHash)
            {
                var tx = txDac.SelectByHash(inputEntity.TransactionHash);

                if (tx != null)
                {
                    var blockEntity = blockDac.SelectByHash(tx.BlockHash);

                    if (blockEntity != null && blockEntity.IsVerified)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #3
0
        public void RefreshUtxoSet(string accountId)
        {
            var outputDac  = new OutputDac();
            var accountDac = new AccountDac();
            var txDac      = new TransactionDac();

            var account = accountDac.SelectById(accountId);

            if (account != null && UtxoSet.Instance != null)
            {
                var set = UtxoSet.Instance.GetUtxoSetByAccountId(accountId);

                if (set != null)
                {
                    set.Clear();

                    //load from database
                    var outputsInDB = outputDac.SelectUnspentByReceiverId(accountId);

                    foreach (var output in outputsInDB)
                    {
                        var msg = new UtxoMsg();
                        msg.AccountId       = output.ReceiverId;
                        msg.TransactionHash = output.TransactionHash;
                        msg.OutputIndex     = output.Index;
                        msg.Amount          = output.Amount;
                        msg.IsConfirmed     = true;
                        msg.IsWatchedOnly   = account.WatchedOnly;

                        var txEntity = txDac.SelectByHash(output.TransactionHash);
                        msg.BlockHash = txEntity != null ? txEntity.BlockHash : null;

                        set.Add(msg);
                    }

                    //load from transaction pool
                    var outputsInTxPool = TransactionPool.Instance.GetTransactionOutputsByAccountId(accountId);

                    foreach (var txHash in outputsInTxPool.Keys)
                    {
                        foreach (var output in outputsInTxPool[txHash])
                        {
                            var msg = new UtxoMsg();
                            msg.AccountId       = accountId;
                            msg.TransactionHash = txHash;
                            msg.OutputIndex     = output.Index;
                            msg.Amount          = output.Amount;
                            msg.IsConfirmed     = false;
                            msg.IsWatchedOnly   = account.WatchedOnly;

                            set.Add(msg);
                        }
                    }
                }
            }
        }
예제 #4
0
        public TransactionMsg CreateNewTransactionMsg(List <UtxoMsg> utxos, Dictionary <string, long> receiverIdAndValues)
        {
            var outputDac  = new OutputDac();
            var accountDac = new AccountDac();

            var transaction = new TransactionMsg();

            transaction.Timestamp = Time.EpochTime;
            transaction.Locktime  = 0;

            foreach (var utxo in utxos)
            {
                var account = accountDac.SelectById(utxo.AccountId);

                if (account == null || account.WatchedOnly)
                {
                    //TODO: throw exception;
                    return(null);
                }

                var privateKey = account.PrivateKey;
                var inputMsg   = new InputMsg();
                inputMsg.OutputTransactionHash = utxo.TransactionHash;
                inputMsg.OutputIndex           = utxo.OutputIndex;
                inputMsg.UnlockScript          = Script.BuildUnlockScript(utxo.TransactionHash, utxo.OutputIndex, Base16.Decode(privateKey), Base16.Decode(account.PublicKey));
                inputMsg.Size = inputMsg.UnlockScript.Length;

                transaction.Inputs.Add(inputMsg);
                outputDac.UpdateSpentStatus(utxo.TransactionHash, utxo.OutputIndex);
            }

            int index = 0;

            foreach (var key in receiverIdAndValues.Keys)
            {
                var value = receiverIdAndValues[key];

                var outputMsg = new OutputMsg();
                outputMsg.Index      = index;
                outputMsg.Amount     = value;
                outputMsg.LockScript = Script.BuildLockScipt(key);
                outputMsg.Size       = outputMsg.LockScript.Length;

                transaction.Outputs.Add(outputMsg);
                index++;
            }

            transaction.Hash = transaction.GetHash();
            return(transaction);
        }
예제 #5
0
        public List <BlockMsg> GetBlockMsgByHeights(List <long> heights)
        {
            var blockDac  = new BlockDac();
            var txDac     = new TransactionDac();
            var inputDac  = new InputDac();
            var outputDac = new OutputDac();
            var blocks    = new List <BlockMsg>();

            foreach (var height in heights)
            {
                var items = blockDac.SelectByHeight(height);

                foreach (var entity in items)
                {
                    blocks.Add(this.convertEntityToBlockMsg(entity));
                }
            }

            return(blocks);
        }
예제 #6
0
        public TransactionMsg ConvertTxEntityToMsg(Transaction tx)
        {
            var inputDac  = new InputDac();
            var outputDac = new OutputDac();

            var txMsg = new TransactionMsg();

            txMsg.Version   = tx.Version;
            txMsg.Hash      = tx.Hash;
            txMsg.Timestamp = tx.Timestamp;
            txMsg.Locktime  = tx.LockTime;

            var inputs  = inputDac.SelectByTransactionHash(tx.Hash);
            var outputs = outputDac.SelectByTransactionHash(tx.Hash);

            foreach (var input in inputs)
            {
                txMsg.Inputs.Add(new InputMsg
                {
                    OutputTransactionHash = input.OutputTransactionHash,
                    OutputIndex           = input.OutputIndex,
                    Size         = input.Size,
                    UnlockScript = input.UnlockScript
                });
            }

            foreach (var output in outputs)
            {
                txMsg.Outputs.Add(new OutputMsg
                {
                    Index      = output.Index,
                    Amount     = output.Amount,
                    Size       = output.Size,
                    LockScript = output.LockScript
                });
            }

            return(txMsg);
        }
예제 #7
0
        public Transaction GetTransactionEntityByHash(string hash)
        {
            var inputDac  = new InputDac();
            var outputDac = new OutputDac();
            var item      = new TransactionDac().SelectByHash(hash);

            if (item != null)
            {
                item.Inputs  = inputDac.SelectByTransactionHash(item.Hash);
                item.Outputs = outputDac.SelectByTransactionHash(item.Hash);
            }
            else
            {
                var msg = TransactionPool.Instance.GetTransactionByHash(hash);

                if (msg != null)
                {
                    item = this.ConvertTxMsgToEntity(msg);
                }
            }

            return(item);
        }
예제 #8
0
        //check whether output is existed. get amount and lockscript from output.
        private bool getOutput(string transactionHash, int outputIndex, out long outputAmount, out string lockScript, out long blockHeight)
        {
            var outputDac    = new OutputDac();
            var outputEntity = outputDac.SelectByHashAndIndex(transactionHash, outputIndex);

            if (outputEntity == null)
            {
                long height    = -1;
                var  outputMsg = TransactionPool.Instance.GetOutputMsg(transactionHash, outputIndex);

                if (outputMsg != null)
                {
                    outputAmount = outputMsg.Amount;
                    lockScript   = outputMsg.LockScript;
                    blockHeight  = height;
                    return(true);
                }
            }
            else
            {
                outputAmount = outputEntity.Amount;
                lockScript   = outputEntity.LockScript;
                var tx = new TransactionDac().SelectByHash(outputEntity.TransactionHash);

                if (tx != null)
                {
                    var blockEntity = new BlockDac().SelectByHash(tx.BlockHash);
                    blockHeight = blockEntity.Height;
                    return(true);
                }
            }

            outputAmount = 0;
            lockScript   = null;
            blockHeight  = -1;
            return(false);
        }
예제 #9
0
        //public List<UtxoMsg> GetAllConfirmedOutputs()
        //{
        //    return UtxoSet.Instance.GetAllUnspentOutputs();
        //}


        public List <UtxoMsg> GetAllConfirmedOutputs()
        {
            List <UtxoMsg> utxoMsgs = new List <UtxoMsg>();

            var outputDac  = new OutputDac();
            var txDac      = new TransactionDac();
            var blockDac   = new BlockDac();
            var accountDac = new AccountDac();

            var lastHeight = -1L;
            var lastBlock  = blockDac.SelectLast();

            if (lastBlock != null)
            {
                lastHeight = lastBlock.Height;
            }
            var outputs = outputDac.SelectAllUnspentOutputs();

            foreach (var output in outputs)
            {
                var msg = new UtxoMsg();
                msg.AccountId       = output.ReceiverId;
                msg.TransactionHash = output.TransactionHash;
                msg.OutputIndex     = output.Index;
                msg.Amount          = output.Amount;
                msg.IsConfirmed     = true;
                var account = accountDac.SelectById(msg.AccountId);
                msg.IsWatchedOnly = account.WatchedOnly;

                var txEntity = txDac.SelectByHash(output.TransactionHash);
                msg.BlockHash = txEntity != null ? txEntity.BlockHash : null;
                utxoMsgs.Add(msg);
            }

            return(utxoMsgs);
        }
예제 #10
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      = 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);
        }
예제 #11
0
        public void SaveBlockIntoDB(BlockMsg msg)
        {
            try
            {
                VerifyBlock(msg);

                Block block = this.convertBlockMsgToEntity(msg);
                block.IsDiscarded = false;
                block.IsVerified  = false;

                var blockDac       = new BlockDac();
                var transactionDac = new TransactionDac();
                var inputDac       = new InputDac();
                var outputDac      = new OutputDac();

                //foreach (var tx in block.Transactions)
                //{
                //    foreach (var input in tx.Inputs)
                //    {
                //        if (input.OutputTransactionHash != Base16.Encode(HashHelper.EmptyHash()))
                //        {
                //            var output = outputDac.SelectByHashAndIndex(input.OutputTransactionHash, input.OutputIndex);

                //            if (output != null)
                //            {
                //                input.AccountId = output.ReceiverId;
                //                outputDac.UpdateSpentStatus(input.OutputTransactionHash, input.OutputIndex);
                //            }
                //        }
                //    }
                //}

                blockDac.Save(block);

                //update nextblock hash
                //blockDac.UpdateNextBlockHash(block.PreviousBlockHash, block.Hash);

                //remove transactions in tx pool
                foreach (var tx in block.Transactions)
                {
                    TransactionPool.Instance.RemoveTransaction(tx.Hash);

                    //save into utxo set
                    foreach (var output in tx.Outputs)
                    {
                        var accountId = AccountIdHelper.CreateAccountAddressByPublicKeyHash(
                            Base16.Decode(
                                Script.GetPublicKeyHashFromLockScript(output.LockScript)
                                )
                            );

                        UtxoSet.Instance.AddUtxoRecord(new UtxoMsg
                        {
                            AccountId       = accountId,
                            BlockHash       = block.Hash,
                            TransactionHash = tx.Hash,
                            OutputIndex     = output.Index,
                            Amount          = output.Amount,
                            IsConfirmed     = true
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.Message, ex);
                throw ex;
            }
        }
예제 #12
0
        public void GetBalanceInDB(out long confirmedBalance, out long unconfirmedBalance)
        {
            //return new OutputDac().SumSelfUnspentOutputs();
            confirmedBalance   = 0;
            unconfirmedBalance = 0;
            var outputDac = new OutputDac();
            var txDac     = new TransactionDac();
            var blockDac  = new BlockDac();

            var lastHeight = -1L;
            var lastBlock  = blockDac.SelectLast();

            if (lastBlock != null)
            {
                lastHeight = lastBlock.Height;
            }

            var outputs = outputDac.SelectAllUnspentOutputs();

            foreach (var output in outputs)
            {
                var tx = txDac.SelectByHash(output.TransactionHash);

                if (tx != null)
                {
                    var block = blockDac.SelectByHash(tx.BlockHash);

                    if (block != null)
                    {
                        if (tx.TotalInput == 0)
                        {
                            //coinbase
                            if (lastHeight - block.Height >= 100)
                            {
                                confirmedBalance += output.Amount;
                            }
                            else
                            {
                                unconfirmedBalance += output.Amount;
                            }
                        }
                        else
                        {
                            if (block.IsVerified)
                            {
                                if (Time.EpochTime >= tx.LockTime)
                                {
                                    confirmedBalance += output.Amount;
                                }
                                else
                                {
                                    unconfirmedBalance += output.Amount;
                                }
                            }
                            else
                            {
                                unconfirmedBalance += output.Amount;
                            }
                        }
                    }
                }
            }
        }
예제 #13
0
        public Transaction ConvertTxMsgToEntity(TransactionMsg txMsg)
        {
            var outputDac = new OutputDac();
            var entity    = new Transaction();

            entity.Hash      = txMsg.Hash;
            entity.BlockHash = null;
            entity.Version   = txMsg.Version;
            entity.Timestamp = txMsg.Timestamp;
            entity.LockTime  = txMsg.Locktime;
            entity.Inputs    = new List <Input>();
            entity.Outputs   = new List <Output>();

            long totalInput  = 0L;
            long totalOutput = 0L;

            foreach (var inputMsg in txMsg.Inputs)
            {
                var input = new Input();
                input.TransactionHash       = txMsg.Hash;
                input.OutputTransactionHash = inputMsg.OutputTransactionHash;
                input.OutputIndex           = inputMsg.OutputIndex;
                input.Size         = inputMsg.Size;
                input.UnlockScript = inputMsg.UnlockScript;

                var output = outputDac.SelectByHashAndIndex(inputMsg.OutputTransactionHash, inputMsg.OutputIndex);

                if (output != null)
                {
                    input.Amount    = output.Amount;
                    input.AccountId = output.ReceiverId;
                }

                entity.Inputs.Add(input);
                totalInput += input.Amount;
            }

            foreach (var outputMsg in txMsg.Outputs)
            {
                var output = new Output();
                output.Index           = outputMsg.Index;
                output.TransactionHash = entity.Hash;
                var address = AccountIdHelper.CreateAccountAddressByPublicKeyHash(
                    Base16.Decode(
                        Script.GetPublicKeyHashFromLockScript(outputMsg.LockScript)
                        ));
                output.ReceiverId = address;
                output.Amount     = outputMsg.Amount;
                output.Size       = outputMsg.Size;
                output.LockScript = outputMsg.LockScript;
                entity.Outputs.Add(output);
                totalOutput += output.Amount;
            }

            entity.TotalInput  = totalInput;
            entity.TotalOutput = totalOutput;
            entity.Fee         = totalInput - totalOutput;
            entity.Size        = txMsg.Size;

            if (txMsg.Inputs.Count == 1 &&
                txMsg.Outputs.Count == 1 &&
                txMsg.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash()))
            {
                entity.Fee = 0;
            }

            return(entity);
        }
예제 #14
0
        public List <Transaction> SearchTransactionEntities(string account, int count, int skip = 0, bool includeWatchOnly = true)
        {
            var inputDac  = new InputDac();
            var outputDac = new OutputDac();
            var items     = new TransactionDac().SelectTransactions(account, count, skip, includeWatchOnly);
            var accounts  = new AccountDac().SelectAll();

            foreach (var item in items)
            {
                item.Inputs  = inputDac.SelectByTransactionHash(item.Hash);
                item.Outputs = outputDac.SelectByTransactionHash(item.Hash);
            }

            if (skip == 0)
            {
                var  txList = TransactionPool.Instance.GetAllTransactions();
                bool containsUnconfirmedTx = false;

                foreach (var tx in txList)
                {
                    var  entity            = this.ConvertTxMsgToEntity(tx);
                    bool isSendTransaction = false;
                    if (entity != null)
                    {
                        foreach (var input in entity.Inputs)
                        {
                            if (accounts.Where(a => a.Id == input.AccountId).Count() > 0)
                            {
                                items.Add(entity);
                                isSendTransaction     = true;
                                containsUnconfirmedTx = true;
                                break;
                            }
                        }

                        if (!isSendTransaction)
                        {
                            foreach (var output in entity.Outputs)
                            {
                                if (accounts.Where(a => a.Id == output.ReceiverId).Count() > 0)
                                {
                                    items.Add(entity);
                                    containsUnconfirmedTx = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (containsUnconfirmedTx)
                {
                    items = items.OrderByDescending(t => t.Timestamp).ToList();
                }
            }
            //var result = new List<TransactionMsg>();

            //foreach(var item in items)
            //{
            //    result.Add(convertTxEntityToMsg(item));
            //}

            //return result;
            return(items);
        }
예제 #15
0
        public TransactionMsg CreateNewTransactionMsg(string senderAccountId, Dictionary <string, long> receiverIdAndValues, long fee)
        {
            var outputDac  = new OutputDac();
            var accountDac = new AccountDac();

            var account = accountDac.SelectById(senderAccountId);

            if (account == null || account.WatchedOnly)
            {
                //TODO: throw exception;
                return(null);
            }

            var  balance     = UtxoSet.Instance.GetAccountBlanace(senderAccountId, true);
            long totalOutput = fee;
            long totalInput  = 0;

            foreach (var key in receiverIdAndValues.Keys)
            {
                totalOutput += receiverIdAndValues[key];
            }

            if (totalOutput > balance)
            {
                //TODO: throw exception
                return(null);
            }

            var transaction = new TransactionMsg();

            transaction.Timestamp = Time.EpochTime;
            transaction.Locktime  = 0;

            var outputs = outputDac.SelectUnspentByReceiverId(senderAccountId);

            foreach (var output in outputs)
            {
                var inputMsg = new InputMsg();
                inputMsg.OutputTransactionHash = output.TransactionHash;
                inputMsg.OutputIndex           = output.Index;
                inputMsg.UnlockScript          = Script.BuildUnlockScript(output.TransactionHash, output.Index, Base16.Decode(account.PrivateKey), Base16.Decode(account.PublicKey));
                inputMsg.Size = inputMsg.UnlockScript.Length;

                transaction.Inputs.Add(inputMsg);
                outputDac.UpdateSpentStatus(output.TransactionHash, output.Index);

                totalInput += output.Amount;
                if (totalInput >= totalOutput)
                {
                    break;
                }
            }

            int index = 0;

            foreach (var key in receiverIdAndValues.Keys)
            {
                var value = receiverIdAndValues[key];

                var outputMsg = new OutputMsg();
                outputMsg.Index      = index;
                outputMsg.Amount     = value;
                outputMsg.LockScript = Script.BuildLockScipt(key);
                outputMsg.Size       = outputMsg.LockScript.Length;

                transaction.Outputs.Add(outputMsg);
                index++;
            }

            if (totalInput > totalOutput)
            {
                var value = totalInput - totalOutput;

                var outputMsg = new OutputMsg();
                outputMsg.Index      = index;
                outputMsg.Amount     = value;
                outputMsg.LockScript = Script.BuildLockScipt(senderAccountId);
                outputMsg.Size       = outputMsg.LockScript.Length;

                transaction.Outputs.Add(outputMsg);
                index++;
            }

            transaction.Hash = transaction.GetHash();

            return(transaction);
        }
예제 #16
0
        public void AddTransactionToPool(TransactionMsg transaction)
        {
            var  accountDac  = new AccountDac();
            var  outputDac   = new OutputDac();
            long feeRate     = 0;
            long totalInput  = 0;
            long totalOutput = 0;

            foreach (var input in transaction.Inputs)
            {
                long   amount;
                string lockCript;
                long   blockHeight;

                if (this.getOutput(input.OutputTransactionHash, input.OutputIndex, out amount, out lockCript, out blockHeight))
                {
                    totalInput += amount;
                }
            }

            foreach (var output in transaction.Outputs)
            {
                totalOutput += output.Amount;
            }

            feeRate = (totalInput - totalOutput) / transaction.Size;

            try
            {
                long fee    = 0;
                var  result = this.VerifyTransaction(transaction, out fee);

                if (result)
                {
                    TransactionPool.Instance.AddNewTransaction(feeRate, transaction);

                    //recheck isolate transactions
                    var txList = TransactionPool.Instance.GetIsolateTransactions();

                    foreach (var tx in txList)
                    {
                        try
                        {
                            if (this.VerifyTransaction(tx, out fee))
                            {
                                TransactionPool.Instance.MoveIsolateTransactionToMainPool(tx.Hash);
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                else
                {
                    TransactionPool.Instance.AddIsolateTransaction(feeRate, transaction);
                }

                foreach (var input in transaction.Inputs)
                {
                    outputDac.UpdateSpentStatus(input.OutputTransactionHash, input.OutputIndex);
                    UtxoSet.Instance.RemoveUtxoRecord(input.OutputTransactionHash, input.OutputIndex);
                }

                foreach (var output in transaction.Outputs)
                {
                    var accountId = AccountIdHelper.CreateAccountAddressByPublicKeyHash(
                        Base16.Decode(
                            Script.GetPublicKeyHashFromLockScript(output.LockScript)
                            )
                        );

                    UtxoSet.Instance.AddUtxoRecord(new UtxoMsg
                    {
                        AccountId       = accountId,
                        BlockHash       = null,
                        TransactionHash = transaction.Hash,
                        OutputIndex     = output.Index,
                        Amount          = output.Amount,
                        IsConfirmed     = false
                    });
                }
            }
            catch (CommonException ex)
            {
                throw ex;
            }
        }
예제 #17
0
        private Block convertBlockMsgToEntity(BlockMsg blockMsg)
        {
            OutputDac outputDac = new OutputDac();

            var block = new Block();

            block.Hash              = blockMsg.Header.Hash;
            block.Version           = blockMsg.Header.Version;
            block.Height            = blockMsg.Header.Height;
            block.PreviousBlockHash = blockMsg.Header.PreviousBlockHash;
            block.Bits              = blockMsg.Header.Bits;
            block.Nonce             = blockMsg.Header.Nonce;
            block.GeneratorId       = blockMsg.Header.GeneratorId;
            block.Timestamp         = blockMsg.Header.Timestamp;
            block.TotalAmount       = 0;
            block.TotalFee          = 0;

            block.Transactions = new List <Transaction>();

            foreach (var txMsg in blockMsg.Transactions)
            {
                var transaction = new Transaction();

                transaction.Hash      = txMsg.Hash;
                transaction.BlockHash = block.Hash;
                transaction.Version   = txMsg.Version;
                transaction.Timestamp = txMsg.Timestamp;
                transaction.LockTime  = txMsg.Locktime;
                transaction.Inputs    = new List <Input>();
                transaction.Outputs   = new List <Output>();

                long totalInput  = 0L;
                long totalOutput = 0L;

                foreach (var inputMsg in txMsg.Inputs)
                {
                    var input = new Input();
                    input.TransactionHash       = txMsg.Hash;
                    input.OutputTransactionHash = inputMsg.OutputTransactionHash;
                    input.OutputIndex           = inputMsg.OutputIndex;
                    input.Size         = inputMsg.Size;
                    input.UnlockScript = inputMsg.UnlockScript;

                    var output = outputDac.SelectByHashAndIndex(inputMsg.OutputTransactionHash, inputMsg.OutputIndex);

                    if (output != null)
                    {
                        input.Amount    = output.Amount;
                        input.AccountId = output.ReceiverId;
                    }

                    transaction.Inputs.Add(input);
                    totalInput += input.Amount;
                }

                foreach (var outputMsg in txMsg.Outputs)
                {
                    var output = new Output();
                    output.Index           = outputMsg.Index;
                    output.TransactionHash = transaction.Hash;
                    var address = AccountIdHelper.CreateAccountAddressByPublicKeyHash(
                        Base16.Decode(
                            Script.GetPublicKeyHashFromLockScript(outputMsg.LockScript)
                            ));
                    output.ReceiverId = address;
                    output.Amount     = outputMsg.Amount;
                    output.Size       = outputMsg.Size;
                    output.LockScript = outputMsg.LockScript;
                    transaction.Outputs.Add(output);
                    totalOutput += output.Amount;
                }

                transaction.TotalInput  = totalInput;
                transaction.TotalOutput = totalOutput;
                transaction.Fee         = totalInput - totalOutput;
                transaction.Size        = txMsg.Size;

                if (txMsg.Inputs.Count == 1 &&
                    txMsg.Outputs.Count == 1 &&
                    txMsg.Inputs[0].OutputTransactionHash == Base16.Encode(HashHelper.EmptyHash()))
                {
                    transaction.Fee = 0;
                }

                block.Transactions.Add(transaction);
                block.TotalAmount += transaction.TotalOutput;
                block.TotalFee    += transaction.Fee;
            }

            //block.GenerationSignature = blockMsg.Header.GenerationSignature;
            block.BlockSignature = blockMsg.Header.BlockSignature;
            //block.CumulativeDifficulty = blockMsg.Header.CumulativeDifficulty;
            block.PayloadHash = blockMsg.Header.PayloadHash;
            block.IsVerified  = false;
            return(block);
        }
예제 #18
0
        public BlockMsg CreateNewBlock(string minerName, 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;

            var blockEntity = blockDac.SelectLast();

            if (blockEntity != null)
            {
                lastBlockHeight = blockEntity.Height;
                lastBlockHash   = blockEntity.Hash;
                lastBlockBits   = blockEntity.Bits;
            }

            long totalSize    = 0;
            long maxSize      = BlockSetting.MAX_BLOCK_SIZE - (500 * 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;
                }
            }

            BlockMsg       newBlockMsg = new BlockMsg();
            BlockHeaderMsg headerMsg   = new BlockHeaderMsg();

            newBlockMsg.Header          = headerMsg;
            headerMsg.Height            = lastBlockHeight + 1;
            headerMsg.PreviousBlockHash = lastBlockHash;


            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 previous4032Block = null;

            if (headerMsg.Height > POW.DiffiucltyAdjustStep)
            {
                previous4032Block = this.GetBlockMsgByHeight(headerMsg.Height - POW.DiffiucltyAdjustStep);
            }

            var newBlockReward = work.GetNewBlockReward();

            headerMsg.Bits             = work.CalculateNextWorkTarget(lastBlockHeight, lastBlockBits, previous4032Block);
            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);
            coinbaseInputMsg.Size = coinbaseInputMsg.UnlockScript.Length;

            var coinbaseOutputMsg = new OutputMsg();

            coinbaseTxMsg.Outputs.Add(coinbaseOutputMsg);
            coinbaseOutputMsg.Amount     = newBlockReward + totalFee;
            coinbaseOutputMsg.LockScript = Script.BuildLockScipt(minerAccount.Id);
            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);
            }

            return(newBlockMsg);
        }