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); }
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); } }
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); } }
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); }
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); }
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); }
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); }
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); }//ネットワーク全体にもらったブロックを発信する