Example #1
0
        async Task HandleRequest(InventoryMessage message, int peerId)
        {
            // Data should not contain anything. (To prevent DDoS)
            if (!message.Data.IsNull())
            {
                throw new ArgumentException();
            }

            byte[] data;
            if (message.IsBlock)
            {
                // ちゃんとしたブロック?
                // ハッシュテーブルのそのブロックあるか見てみる
                if (!Blocks.TryGetValue(message.ObjectId, out data))
                {
                    return;
                }
            }
            else
            {
                Transaction tx;
                // ちゃんとしたトランザクション
                if (!MemoryPool.TryGetValue(message.ObjectId, out tx))
                {
                    return;
                }
                data = tx.Original;
            }

            message.Type = Body;
            message.Data = data;
            // 送ってあげる
            await ConnectionManager.SendAsync(message, peerId);
        }
Example #2
0
        public Task HandleMessage(InventoryMessage message, int peerId)
        {
            switch (message.Type)
            {
            case Advertise: return(HandleAdvertise(message, peerId));

            case Request: return(HandleRequest(message, peerId));

            case Body: return(HandleBody(message, peerId));

            default: return(Task.CompletedTask);
            }
        }
Example #3
0
        public Task HandleMessage(InventoryMessage message, int peerId)
        {
            switch (message.Type)
            {
            // このブロック・トランザクション持ってますか?
            case Advertise: return(HandleAdvertise(message, peerId));

            // くれ!
            case Request: return(HandleRequest(message, peerId));

            // あげる!
            case Body: return(HandleBody(message, peerId));

            default: return(Task.CompletedTask);
            }
        }
Example #4
0
        async Task HandleAdvertise(InventoryMessage message, int peerId)
        {
            // Data should not contain anything. (To prevent DDoS)
            if (!message.Data.IsNull())
            {
                throw new ArgumentException();
            }

            var haveObject = message.IsBlock ?
                             Blocks.ContainsKey(message.ObjectId) :
                             MemoryPool.ContainsKey(message.ObjectId);

            if (haveObject)
            {
                return;
            }

            message.Type = Request;
            await ConnectionManager.SendAsync(message, peerId);
        }
Example #5
0
        async Task HandleBody(InventoryMessage message, int peerId)
        {
            if (message.IsBlock)
            {
                var block = TryLoadBlock(message.ObjectId, message.Data);
                if (block.IsNull())
                {
                    return;
                }

                var prevId = block.PreviousHash;
                if (!Blocks.ContainsKey(prevId))
                {
                    // Otherwise, ask the sending peer to provide previous block.
                    await ConnectionManager.SendAsync(new InventoryMessage
                    {
                        Type     = Request,
                        IsBlock  = true,
                        ObjectId = prevId,
                    }, peerId);
                }
            }
            else
            {
                var success = TryAddTransactionToMemoryPool(
                    message.ObjectId, message.Data);
                if (!success)
                {
                    return;
                }
            }

            message.Type = Advertise;
            message.Data = null;
            await ConnectionManager.BroadcastAsync(message, peerId);
        }
Example #6
0
        async Task HandleBody(InventoryMessage message, int peerId)
        {
            // Data should not exceed the maximum size.
            var data = message.Data;

            if (data.Length > MaximumBlockSize)
            {
                throw new ArgumentException();
            }

            // ハッシュ値正しい?
            var id = message.IsBlock ?
                     BlockchainUtil.ComputeBlockId(data) :
                     Hash.ComputeDoubleSHA256(data);

            if (!ByteString.CopyFrom(id).Equals(message.ObjectId))
            {
                return;
            }

            if (message.IsBlock)
            {
                // ミューテックス
                lock (Blocks)
                {
                    if (Blocks.ContainsKey(message.ObjectId))
                    {
                        return;
                    }
                    // ハッシュテーブルに追加
                    Blocks.Add(message.ObjectId, data);
                }

                var block = BlockchainUtil.DeserializeBlock(data);
                // 前のブロックも知らなかったら前のももらう
                var prevId = block.PreviousHash;
                if (!Blocks.ContainsKey(prevId))
                {
                    await ConnectionManager.SendAsync(new InventoryMessage
                    {
                        Type     = Request,
                        IsBlock  = true,
                        ObjectId = prevId,
                    }, peerId);
                }
                Executor.ProcessBlock(block);
            }
            else
            {
                if (MemoryPool.ContainsKey(message.ObjectId))
                {
                    return;
                }

                var tx = BlockchainUtil.DeserializeTransaction(data);

                // Ignore the coinbase transactions.
                if (tx.InEntries.Count == 0)
                {
                    return;
                }

                lock (MemoryPool)
                {
                    if (MemoryPool.ContainsKey(message.ObjectId))
                    {
                        return;
                    }
                    MemoryPool.Add(message.ObjectId, tx);
                }
            }

            message.Type = Advertise;
            message.Data = null;
            // 他の人に教えてあげる
            await ConnectionManager.BroadcastAsync(message, peerId);
        }
Example #7
0
        void MineFromLastBlock(CancellationToken token)
        {
            // Takeout memory pool transactions.
            var size = 350; // Estimated block header + coinbase size
            var txs  = InventoryManager.MemoryPool
                       .Select(tx => tx.Value)
                       .TakeWhile(tx => (size += tx.Original.Length + 50)
                                  < InventoryManager.MaximumBlockSize)
                       .ToList(); // Iteration should end immediately.

            // Choose transactions that are valid.
            var   blockTime = DateTime.UtcNow;
            ulong coinbase  = BlockParameter.GetCoinbase(Executor.Latest.Height + 1);
            var   spent     = new List <TransactionOutput>();

            txs = txs.Where(tx =>
            {
                try
                {
                    token.ThrowIfCancellationRequested();
                    Executor.Run(tx, blockTime, spentTxo: spent);

                    var exec  = tx.ExecInfo;
                    coinbase += exec.TransactionFee;
                    spent.AddRange(exec.RedeemedOutputs);
                    return(true);
                }
                catch { return(false); }
            }).ToList();

            // Create coinbase transaction structure.
            var coinbaseTx = new Transaction
            {
                Timestamp  = blockTime,
                InEntries  = new List <InEntry>(),
                OutEntries = new List <OutEntry>
                {
                    new OutEntry
                    {
                        RecipientHash = RecipientAddress,
                        Amount        = coinbase,
                    },
                },
            };

            // We need backing byte-encoded behind.
            coinbaseTx = DeserializeTransaction(Serialize(coinbaseTx));
            Executor.Run(coinbaseTx, blockTime, coinbase);
            txs.Insert(0, coinbaseTx);

            // Calculate root hash.
            var txIds = txs.Select(x => x.Id).ToList();
            var block = new Block
            {
                PreviousHash = Executor.Latest.Id,
                Difficulty   = BlockParameter.GetNextDifficulty(
                    Executor.Latest.Ancestors(Executor.Blocks)),
                MerkleRoot = CalculateMerkleRoot(txs),
            };

            if (!Mine(block, token))
            {
                return;
            }

            block.TransactionIds     = txIds;
            block.Transactions       = txs.Select(x => x.Original).ToList();
            block.ParsedTransactions = txs.ToArray();

            logger.LogInformation("Block mined: {0}",
                                  JsonConvert.SerializeObject(block, Formatting.Indented));

            var msg = new InventoryMessage
            {
                Data     = Serialize(block),
                ObjectId = block.Id,
                IsBlock  = true,
                Type     = InventoryMessageType.Body,
            };

            ConnectionManager.BroadcastAsync(msg);
            InventoryManager.HandleMessage(msg, -1);
        }
Example #8
0
        async Task HandleBody(InventoryMessage message, int peerId)
        {
            // Data should not exceed the maximum size.
            var data = message.Data;

            if (data.Length > MaximumBlockSize)
            {
                throw new ArgumentException();
            }

            var id = message.IsBlock ?
                     BlockchainUtil.ComputeBlockId(data) :
                     Hash.ComputeDoubleSHA256(data);

            if (!ByteString.CopyFrom(id).Equals(message.ObjectId))
            {
                return;
            }

            if (message.IsBlock)
            {
                lock (Blocks)//並列処理を避ける
                {
                    if (Blocks.ContainsKey(message.ObjectId))
                    {
                        return;
                    }
                    Blocks.Add(message.ObjectId, data);
                }

                var prevId = Deserialize <Block>(data).PreviousHash;
                if (!Blocks.ContainsKey(prevId))
                {
                    await ConnectionManager.SendAsync(new InventoryMessage//当該ブロックの前のブロックを持っていない場合はそれもRequestする(前のblockのIDが必要なため
                    {
                        Type     = Request,
                        IsBlock  = true,
                        ObjectId = prevId,
                    }, peerId);
                }
                else
                {
                    Executor.ProcessBlock(data, prevId);
                }
            }
            else
            {
                if (MemoryPool.ContainsKey(message.ObjectId))
                {
                    return;
                }

                var tx = BlockchainUtil.DeserializeTransaction(data);

                // Ignore the coinbase transactions.
                if (tx.InEntries.Count == 0)
                {
                    return;
                }

                lock (MemoryPool)
                {
                    if (MemoryPool.ContainsKey(message.ObjectId))
                    {
                        return;
                    }
                    MemoryPool.Add(message.ObjectId, tx);
                }
            }

            message.Type = Advertise;
            message.Data = null;
            await ConnectionManager.BroadcastAsync(message, peerId);
        }//ネットワーク全体にもらったブロックを発信する