private void OnGetDataMessageReceived(InvPayload payload) { foreach (UInt256 hash in payload.Hashes.Distinct()) { IInventory inventory; if (!localNode.RelayCache.TryGet(hash, out inventory) && !localNode.ServiceEnabled) { continue; } switch (payload.Type) { case InventoryType.TX: if (inventory == null) { inventory = LocalNode.GetTransaction(hash); } if (inventory == null && Blockchain.Default != null) { inventory = Blockchain.Default.GetTransaction(hash); } if (inventory != null) { EnqueueMessage("tx", inventory); } break; case InventoryType.Block: if (inventory == null && Blockchain.Default != null) { inventory = Blockchain.Default.GetBlock(hash); } if (inventory != null) { BloomFilter filter = bloom_filter; if (filter == null) { EnqueueMessage("block", inventory); } else { Block block = (Block)inventory; BitArray flags = new BitArray(block.Transactions.Select(p => TestFilter(filter, p)).ToArray()); EnqueueMessage("merkleblock", MerkleBlockPayload.Create(block, flags)); } } break; case InventoryType.Consensus: if (inventory != null) { EnqueueMessage("consensus", inventory); } break; } } }
private bool OnBroadcastCommand(string[] args) { string command = args[1].ToLower(); ISerializable payload = null; switch (command) { case "addr": payload = AddrPayload.Create(NetworkAddressWithTime.Create(new IPEndPoint(IPAddress.Parse(args[2]), ushort.Parse(args[3])), NetworkAddressWithTime.NODE_NETWORK, DateTime.UtcNow.ToTimestamp())); break; case "block": if (args[2].Length == 64 || args[2].Length == 66) { payload = Blockchain.Default.GetBlock(UInt256.Parse(args[2])); } else { payload = Blockchain.Default.GetBlock(uint.Parse(args[2])); } break; case "getblocks": case "getheaders": payload = GetBlocksPayload.Create(UInt256.Parse(args[2])); break; case "getdata": case "inv": payload = InvPayload.Create(Enum.Parse <InventoryType>(args[2], true), args.Skip(3).Select(UInt256.Parse).ToArray()); break; case "tx": payload = LocalNode.GetTransaction(UInt256.Parse(args[2])) ?? Blockchain.Default.GetTransaction(UInt256.Parse(args[2])); break; case "alert": case "consensus": case "filteradd": case "filterload": case "headers": case "merkleblock": case "ping": case "pong": case "reject": case "verack": case "version": Console.WriteLine($"Command \"{command}\" is not supported."); return(true); } foreach (RemoteNode node in LocalNode.GetRemoteNodes()) { node.EnqueueMessage(command, payload); } return(true); }
public void DeserializeAndSerialize() { var test = InvPayload.Create(InventoryType.TX, UInt256.Zero, UInt256.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); var clone = test.ToArray().AsSerializable <InvPayload>(); Assert.AreEqual(test.Type, clone.Type); CollectionAssert.AreEqual(test.Hashes, clone.Hashes); Assert.ThrowsException <FormatException>(() => InvPayload.Create((InventoryType)0xff, UInt256.Zero).ToArray().AsSerializable <InvPayload>()); }
public void TryDeserialize_0Count_Test() { var pl = new InvPayload(); var stream = new FastStreamReader(new byte[1]); bool success = pl.TryDeserialize(stream, out string error); Assert.True(success, error); Assert.Null(error); Assert.Empty(pl.InventoryList); }
void NewNodeMessage(IncomingMessage message) { if (message.Message.Payload is VerAckPayload) { _Nodes.Add(message.Node); } if (message.Message.Payload is InvPayload) { InvPayload invPayload = (InvPayload)message.Message.Payload; message.Node.SendMessage(new GetDataPayload(invPayload.Inventory.ToArray())); } if (message.Message.Payload is TxPayload) { TxPayload txPayload = (TxPayload)message.Message.Payload; _ReceivedTransactions.AddOrUpdate(txPayload.Object.GetHash(), txPayload.Object, (k, v) => v); } if (message.Message.Payload is GetHeadersPayload) { var headers = (GetHeadersPayload)message.Message.Payload; var fork = _Server.ChainBuilder.Chain.FindFork(headers.BlockLocators); var response = _Server.ChainBuilder.Chain .ToEnumerable(true) .TakeWhile(f => f.HashBlock != fork.HashBlock && f.HashBlock != headers.HashStop) .Select(f => f.Header) .ToArray(); HeadersPayload res = new HeadersPayload(); res.Headers.AddRange(response); message.Node.SendMessage(res); } if (message.Message.Payload is GetDataPayload) { Transaction tx; Block block; var getData = message.Message.Payload as GetDataPayload; foreach (var inv in getData.Inventory) { if (inv.Type == InventoryType.MSG_TX) { if (_Transactions.TryGetValue(inv.Hash, out tx)) { message.Node.SendMessage(new TxPayload(tx)); } } if (inv.Type == InventoryType.MSG_BLOCK) { if (_Blocks.TryGetValue(inv.Hash, out block)) { message.Node.SendMessage(new BlockPayload(block)); } } } } }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) { return; } if (payload.ValidatorIndex != context.PrimaryIndex) { return; } if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}"); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) { return; } context.Signatures = new byte[context.Validators.Length][]; context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } } if (!AddTransaction(message.MinerTransaction, true)) { return; } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); LocalNode.AllowHashes(hashes); InvPayload msg = InvPayload.Create(InventoryType.TX, hashes); foreach (RemoteNode node in localNode.GetRemoteNodes()) { node.EnqueueMessage("getdata", msg); } } }
private void InitializeConsensus(byte view_number) { lock (context) { if (view_number == 0) { context.Reset(wallet); } else { context.ChangeView(view_number); } if (context.MyIndex < 0) { return; } Log($"initialize: height={context.BlockIndex} view={view_number} index={context.MyIndex} role={(context.MyIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}"); if (context.MyIndex == context.PrimaryIndex) { context.State |= ConsensusState.Primary; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { FillContext(); } if (context.TransactionHashes.Length > 1) { InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray()); foreach (RemoteNode node in localNode.GetRemoteNodes()) { node.EnqueueMessage("inv", invPayload); } } timer_height = context.BlockIndex; timer_view = view_number; // 议长发起共识时间控制 TimeSpan span = DateTime.Now - block_received_time; if (span >= Blockchain.TimePerBlock) { timer.Change(0, Timeout.Infinite);// 间隔时间大于预订时间则立即发起共识 } else { timer.Change(Blockchain.TimePerBlock - span, Timeout.InfiniteTimeSpan);// 定时执行 } } else { context.State = ConsensusState.Backup; timer_height = context.BlockIndex; timer_view = view_number; // 议员超时控制 t * 2 ^ (view_number + 1) timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan); } } }
/// <summary> /// Processing of inventory payload message from the peer. /// Adds inventory to known inventory then sends GetDataPayload to the attached peer. /// </summary> /// <param name="peer">The peer sending the message.</param> /// <param name="invPayload">The inventory payload in the message.</param> async Task ProcessInvAsync(INetworkPeer peer, InvPayload invPayload) { Guard.NotNull(peer, nameof(peer)); if (invPayload.Inventory.Count > ConnectionManager.MaxInventorySize) { this.logger.LogTrace("(-)[MAX_INV_SZ]"); //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving return; //error("message inv size() = %u", vInv.size()); } if (this.initialBlockDownloadState.IsInitialBlockDownload()) { this.logger.LogTrace("(-)[IS_IBD]"); return; } //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); var inventoryTxs = invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)); lock (this.lockObject) { foreach (var inv in inventoryTxs) { this.filterInventoryKnown.Add(inv.Hash); } } var send = new GetDataPayload(); foreach (var inv in inventoryTxs) { if (await this.orphans.AlreadyHaveAsync(inv.Hash).ConfigureAwait(false)) { this.logger.LogDebug("Transaction ID '{0}' already in orphans, skipped.", inv.Hash); continue; } if (this.isBlocksOnlyMode) { this.logger.LogDebug("Transaction ID '{0}' inventory sent in violation of protocol peer '{1}'.", inv.Hash, peer.RemoteSocketEndpoint); continue; } send.Inventory.Add(new InventoryVector(peer.AddSupportedOptions(InventoryType.MSG_TX), inv.Hash)); } if (peer.IsConnected && send.Inventory.Count > 0) { this.logger.LogDebug("Asking for transaction data from peer '{0}'.", peer.RemoteSocketEndpoint); await peer.SendMessageAsync(send).ConfigureAwait(false); } }
/// <summary> /// Sends transaction to peers. /// </summary> /// <param name="transaction">Transaction that will be propagated.</param> /// <param name="peers">Peers to whom we will propagate the transaction.</param> protected async Task PropagateTransactionToPeersAsync(Transaction transaction, List <NetworkPeer> peers) { this.AddOrUpdate(transaction, State.ToBroadcast); var invPayload = new InvPayload(transaction); foreach (var peer in peers) { await peer.SendMessageAsync(invPayload); } }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!_context.State.HasFlag(ConsensusState.Backup) || _context.State.HasFlag(ConsensusState.RequestReceived)) { return; } if (payload.ValidatorIndex != _context.PrimaryIndex) { return; } if (payload.Timestamp <= _context.Snapshot.GetHeader(_context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}", LogLevel.Warning); return; } _context.State |= ConsensusState.RequestReceived; _context.Timestamp = payload.Timestamp; _context.Nonce = message.Nonce; _context.NextConsensus = message.NextConsensus; _context.TransactionHashes = message.TransactionHashes; _context.Transactions = new Dictionary <UInt256, Transaction>(); if (!Crypto.Default.VerifySignature(_context.MakeHeader().GetHashData(), message.Signature, _context.Validators[payload.ValidatorIndex].EncodePoint(false))) { return; } _context.Signatures = new byte[_context.Validators.Length][]; _context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempool = Blockchain.Singleton.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in _context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } } if (!AddTransaction(message.MinerTransaction, true)) { return; } if (_context.Transactions.Count < _context.TransactionHashes.Length) { UInt256[] hashes = _context.TransactionHashes.Where(i => !_context.Transactions.ContainsKey(i)).ToArray(); _system.TaskManager.Tell(new TaskManager.RestartTasks { Payload = InvPayload.Create(InventoryType.Tx, hashes) }); } }
private void OnGetDataMessageReceived(Message msg) { InvPayload payload = msg.GetPayload <InvPayload>(); if (sentHashes.Add(payload.Hashes[0])) { if (OnGetInventoryData(payload.Hashes[0], payload.Type)) { Context.Parent.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Send, payload.Type, 1)); } } }
private void ProcessInvPayload(InvPayload invPayload) { // if node has transaction we broadcast foreach (InventoryVector inv in invPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX)) { BroadcastTransactionStateChanedEntry txEntry = this.broadcasterManager.GetTransaction(inv.Hash); if (txEntry != null) { this.broadcasterManager.AddOrUpdate(txEntry.Transaction, TransactionBroadcastState.Propagated); } } }
private void OnRestartTasks(InvPayload payload) { knownHashes.ExceptWith(payload.Hashes); foreach (UInt256 hash in payload.Hashes) { globalTasks.Remove(hash); } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, payload.Hashes)) { system.LocalNode.Tell(Message.Create(MessageCommand.GetData, group)); } }
private void ProcessInvPayload(InvPayload invPayload) { // if node has tx we broadcasted foreach (var inv in invPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX)) { var txEntry = this.manager.GetTransaction(inv.Hash); if (txEntry != null) { this.manager.AddOrUpdate(txEntry.Transaction, State.Propagated); } } }
private void RequestTasks(TaskSession session) { if (session.HasTask) { return; } if (session.AvailableTasks.Count > 0) { session.AvailableTasks.ExceptWith(knownHashes); session.AvailableTasks.RemoveWhere(p => Blockchain.Singleton.ContainsBlock(p)); HashSet <UInt256> hashes = new HashSet <UInt256>(session.AvailableTasks); if (hashes.Count > 0) { foreach (UInt256 hash in hashes.ToArray()) { if (!IncrementGlobalTask(hash)) { hashes.Remove(hash); } } session.AvailableTasks.ExceptWith(hashes); foreach (UInt256 hash in hashes) { session.Tasks[hash] = DateTime.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(InventoryType.Block, hashes.ToArray())) { session.RemoteNode.Tell(Message.Create(MessageCommand.GetData, group)); } return; } } if ((!HasHeaderTask || globalTasks[HeaderTaskHash] < MaxConncurrentTasks) && Blockchain.Singleton.HeaderHeight < session.StartHeight) { session.Tasks[HeaderTaskHash] = DateTime.UtcNow; IncrementGlobalTask(HeaderTaskHash); session.RemoteNode.Tell(Message.Create(MessageCommand.GetHeaders, GetBlocksPayload.Create(Blockchain.Singleton.CurrentHeaderHash))); } else if (Blockchain.Singleton.Height < session.StartHeight) { UInt256 hash = Blockchain.Singleton.CurrentBlockHash; for (uint i = Blockchain.Singleton.Height + 1; i <= Blockchain.Singleton.HeaderHeight; i++) { hash = Blockchain.Singleton.GetBlockHash(i); if (!globalTasks.ContainsKey(hash)) { hash = Blockchain.Singleton.GetBlockHash(i - 1); break; } } session.RemoteNode.Tell(Message.Create(MessageCommand.GetBlocks, GetBlocksPayload.Create(hash))); } }
public void ConstructorTest() { var invs = new Inventory[] { new Inventory(InventoryType.Block, new byte[32]), new Inventory(InventoryType.CompactBlock, Helper.GetBytes(32)) }; var pl = new InvPayload(invs); Assert.Equal(PayloadType.Inv, pl.PayloadType); Assert.Same(invs, pl.InventoryList); }
/// <summary> /// Processes "inv" message received from the peer. /// </summary> /// <param name="invPayload">Payload of "inv" message to process.</param> private async Task ProcessInvAsync(InvPayload invPayload) { this.logger.LogTrace("({0}:'{1}')", nameof(invPayload), invPayload); if (invPayload.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !this.chain.Contains(i.Hash))) { // No need of periodical refresh, the peer is notifying us. this.refreshTimer.Dispose(); await this.TrySyncAsync().ConfigureAwait(false); } this.logger.LogTrace("(-)"); }
void ProcessInvPayload(InvPayload payload) { var unknownBlocks = new List <InvEntryPayload>(); foreach (InvEntryPayload entry in payload.Entries) { if (entry.Type == InvEntryType.MSG_BLOCK) { unknownBlocks.Add(entry); } } Connection.SendGetDataMessage(new InvPayload(unknownBlocks)); }
private void OnRelay(IInventory inventory) { if (!IsFullNode) { return; } //if (inventory.InventoryType == InventoryType.TX) //{ // if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory)) // return; //} EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash)); }
public void EnqueueMessage(string command, ISerializable payload = null) { TR.Enter(); if (command == "inv") { InvPayload inv = (InvPayload)payload; TR.Log("message : {0} to {1} with {2}", command, RemoteEndpoint.Address, inv.Hashes[0].ToString()); } else { TR.Log("message : {0} to {1}", command, RemoteEndpoint.Address); } bool is_single = false; switch (command) { case "addr": case "getaddr": case "getblocks": case "getheaders": case "mempool": is_single = true; break; } Queue <Message> message_queue; switch (command) { case "alert": case "consensus": case "filteradd": case "filterclear": case "filterload": case "getaddr": case "mempool": message_queue = message_queue_high; break; default: message_queue = message_queue_low; break; } lock (message_queue) { if (!is_single || message_queue.All(p => p.Command != command)) { message_queue.Enqueue(Message.Create(command, payload)); } } TR.Exit(); }
private void OnGetTxnMessageReceived(Message msg) { InvPayload payload = msg.GetPayload <InvPayload>(); if (payload.Type != InventoryType.TX) { throw new InvalidOperationException(); } UInt256[] hashes = payload.Hashes.Where(p => sentHashes.Add(p)).ToArray(); if (hashes.Length == 0) { return; } blockchain.Log($"OnGetTxn begin, count:{payload.Hashes.Length}, [{remoteNode.Remote.Address}]", Plugins.LogLevel.Debug); List <Transaction> transactions = new List <Transaction>(); foreach (UInt256 hash in hashes) { Transaction tx = blockchain.GetTransaction(hash); if (tx != null) { transactions.Add(tx); } } int count = transactions.Count; if (count > 0) { if (ProtocolSettings.Default.EnableCompressedRawTxn) { foreach (CompressedTransactionPayload ctx_payload in CompressedTransactionPayload.CreateGroup(transactions.ToArray())) { Context.Parent.Tell(Message.Create(MessageType.CompressedTxn, ctx_payload)); } } else { foreach (RawTransactionPayload rtx_payload in RawTransactionPayload.CreateGroup(transactions.ToArray())) { Context.Parent.Tell(Message.Create(MessageType.RawTxn, rtx_payload)); } } Context.Parent.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Send, payload.Type, count)); } blockchain.Log($"OnGetTxn end, count:{hashes.Length}=>{count}, [{remoteNode.Remote.Address}]", Plugins.LogLevel.Debug); }
/// <summary> /// Sends transaction to peers. /// </summary> /// <param name="transaction">Transaction that will be propagated.</param> /// <param name="skipHalfOfThePeers">If set to <c>true</c> transaction will be send to all the peers we are connected to. Otherwise it will be sent to half of them.</param> protected void PropagateTransactionToPeers(Transaction transaction, bool skipHalfOfThePeers = false) { this.AddOrUpdate(transaction, State.ToBroadcast); var invPayload = new InvPayload(transaction); var peers = this.connectionManager.ConnectedNodes.ToList(); int propagateToCount = skipHalfOfThePeers ? (int)Math.Ceiling(peers.Count / 2.0) : peers.Count; for (int i = 0; i < propagateToCount; ++i) { peers[i].SendMessageAsync(invPayload).GetAwaiter().GetResult(); } }
async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload) { // TODO: bring logic from core foreach (var item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK))) { var chainedHeaderBlock = this.consensusManager.GetBlockData(item.Hash); if (chainedHeaderBlock?.Block != null) { this.logger.LogDebug("Sending block '{0}' to peer '{1}'.", chainedHeaderBlock.ChainedHeader, peer.RemoteSocketEndpoint); //TODO strip block of witness if node does not support await peer.SendMessageAsync(new BlockPayload(chainedHeaderBlock.Block.WithOptions( this.ChainIndexer.Network.Consensus.ConsensusFactory, peer.SupportedTransactionOptions))) .ConfigureAwait(false); } else { this.logger.LogDebug("Block with hash '{0}' requested from peer '{1}' was not found in store.", item.Hash, peer.RemoteSocketEndpoint); } // If the peer is syncing using "getblocks" message we are supposed to send // an "inv" message with our tip to it once it asks for all blocks // from the previous batch. if (item.Hash == this.getBlocksBatchLastItemHash) { // Reset the hash to indicate that no continuation is pending anymore. this.getBlocksBatchLastItemHash = null; // Announce last block we have in the store. var blockStoreTip = this.blockStoreQueue.BlockStoreCacheTip; if (blockStoreTip != null) { this.logger.LogDebug("Sending continuation inventory message for block '{0}' to peer '{1}'.", blockStoreTip, peer.RemoteSocketEndpoint); var invContinue = new InvPayload(); invContinue.Inventory.Add(new InventoryVector(InventoryType.MSG_BLOCK, blockStoreTip.HashBlock)); await peer.SendMessageAsync(invContinue).ConfigureAwait(false); } else { this.logger.LogDebug("Reorg in blockstore, inventory continuation won't be sent to peer '{0}'.", peer.RemoteSocketEndpoint); } } } }
private void OnInvMessageReceived(InvPayload payload) { TR.Enter(); if (payload.Type != InventoryType.TX && payload.Type != InventoryType.Block && payload.Type != InventoryType.Consensus) { TR.Exit(); return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); lock (LocalNode.KnownHashes) { hashes.RemoveWhere(p => LocalNode.KnownHashes.TryGetValue(p, out DateTime time) && time + LocalNode.HashesExpiration >= DateTime.UtcNow); } if (hashes.Count == 0) { TR.Exit(); return; } lock (missions_global) { lock (missions) { if (localNode.GlobalMissionsEnabled) { hashes.RemoveWhere(p => missions_global.TryGetValue(p, out DateTime time) && time + MissionExpiration >= DateTime.UtcNow); } if (hashes.Count > 0) { if (missions.Count == 0) { mission_start = DateTime.Now; } foreach (UInt256 hash in hashes) { if (!missions_global.ContainsKey(hash)) { missions_global.Add(hash, DateTime.UtcNow); } } missions.UnionWith(hashes); } } } if (hashes.Count == 0) { TR.Exit(); return; } EnqueueMessage("getdata", InvPayload.Create(payload.Type, hashes.ToArray())); TR.Exit(); }
private void OnRelay(IInventory inventory) { if (Version?.Services.HasFlag(VersionServices.AcceptRelay) != true) { return; } if (inventory.InventoryType == InventoryType.TX) { if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory)) { return; } } EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash)); }
public void TryDeserializeTest(Inventory[] items, byte[] data) { var pl = new InvPayload(); var stream = new FastStreamReader(data); bool success = pl.TryDeserialize(stream, out string error); Assert.True(success, error); Assert.Null(error); Assert.Equal(items.Length, pl.InventoryList.Length); for (int i = 0; i < items.Length; i++) { Assert.Equal(items[i].InvType, pl.InventoryList[i].InvType); Assert.Equal(items[i].Hash, pl.InventoryList[i].Hash); } }
private void OnRelay(IInventory inventory) { if (Version?.Relay != true) { return; } if (inventory.InventoryType == InventoryType.TX) { if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory)) { return; } } EnqueueMessage("inv", InvPayload.Create(inventory.InventoryType, inventory.Hash)); }
private async Task BroadcastTransactionToNetworkNodeAsync(SmartTransaction transaction, Node node) { Logger.LogInfo($"Trying to broadcast transaction with random node ({node.RemoteSocketAddress}):{transaction.GetHash()}."); if (!BitcoinStore.MempoolService.TryAddToBroadcastStore(transaction.Transaction, node.RemoteSocketEndpoint.ToString())) // So we'll reply to INV with this transaction. { Logger.LogWarning($"Transaction {transaction.GetHash()} was already present in the broadcast store."); } var invPayload = new InvPayload(transaction.Transaction); // Give 7 seconds to send the inv payload. await node.SendMessageAsync(invPayload).WithAwaitCancellationAsync(TimeSpan.FromSeconds(7)).ConfigureAwait(false); // ToDo: It's dangerous way to cancel. Implement proper cancellation to NBitcoin! if (BitcoinStore.MempoolService.TryGetFromBroadcastStore(transaction.GetHash(), out TransactionBroadcastEntry? entry)) { // Give 7 seconds for serving. var timeout = 0; while (!entry.IsBroadcasted()) { if (timeout > 7) { throw new TimeoutException("Did not serve the transaction."); } await Task.Delay(1_000).ConfigureAwait(false); timeout++; } node.DisconnectAsync("Thank you!"); Logger.LogInfo($"Disconnected node: {node.RemoteSocketAddress}. Successfully broadcasted transaction: {transaction.GetHash()}."); // Give 21 seconds for propagation. timeout = 0; while (entry.GetPropagationConfirmations() < 2) { if (timeout > 21) { throw new TimeoutException("Did not serve the transaction."); } await Task.Delay(1_000).ConfigureAwait(false); timeout++; } Logger.LogInfo($"Transaction is successfully propagated: {transaction.GetHash()}."); } else { Logger.LogWarning($"Expected transaction {transaction.GetHash()} was not found in the broadcast store."); } }
private async Task ProcessInventoryAsync(Node node, InvPayload invPayload) { var getDataPayload = new GetDataPayload(); foreach (var inv in invPayload.Inventory) { if (ProcessInventoryVector(inv, node.RemoteSocketEndpoint)) { getDataPayload.Inventory.Add(inv); } } if (getDataPayload.Inventory.Any() && node.IsConnected) { await node.SendMessageAsync(getDataPayload).ConfigureAwait(false); } }
private void SendPrepareRequest() { Log($"send prepare request: height={context.BlockIndex} view={context.ViewNumber}"); localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareRequest() }); if (context.TransactionHashes.Length > 1) { foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray())) { localNode.Tell(Message.Create("inv", payload)); } } ChangeTimer(TimeSpan.FromSeconds((Blockchain.SecondsPerBlock << (context.ViewNumber + 1)) - (context.ViewNumber == 0 ? Blockchain.SecondsPerBlock : 0))); }