private Swarm <DumbAction> CreateSwarm( PrivateKey privateKey = null, AppProtocolVersion?appProtocolVersion = null, int tableSize = Kademlia.TableSize, int bucketSize = Kademlia.BucketSize, string host = null, int?listenPort = null, DateTimeOffset?createdAt = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, IEnumerable <PublicKey> trustedAppProtocolVersionSigners = null, SwarmOptions options = null) { var policy = new BlockPolicy <DumbAction>(new MinerReward(1)); var fx = new DefaultStoreFixture(memory: true, blockAction: policy.BlockAction); var blockchain = TestUtils.MakeBlockChain(policy, fx.Store, fx.StateStore); return(CreateSwarm( blockchain, privateKey, appProtocolVersion, tableSize, bucketSize, host, listenPort, createdAt, iceServers, differentAppProtocolVersionEncountered, trustedAppProtocolVersionSigners, options)); }
private static bool IsAppProtocolVersionValid( Peer remotePeer, AppProtocolVersion localVersion, AppProtocolVersion remoteVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered) { if (remoteVersion.Equals(localVersion)) { return(true); } if (!(trustedAppProtocolVersionSigners is null) && !trustedAppProtocolVersionSigners.Any(remoteVersion.Verify)) { return(false); } if (differentAppProtocolVersionEncountered is null) { return(false); } return(differentAppProtocolVersionEncountered(remotePeer, remoteVersion, localVersion)); }
private TcpTransport CreateTcpTransport( PrivateKey privateKey = null, AppProtocolVersion appProtocolVersion = default, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners = null, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, TimeSpan?messageTimestampBuffer = null ) { privateKey = privateKey ?? new PrivateKey(); host = host ?? IPAddress.Loopback.ToString(); iceServers = iceServers ?? new IceServer[] { }; return(new TcpTransport( privateKey, appProtocolVersion, trustedAppProtocolVersionSigners, host, listenPort, iceServers, differentAppProtocolVersionEncountered, messageTimestampBuffer)); }
public KademliaProtocol( ITransport transport, Address address, AppProtocolVersion appProtocolVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered, ILogger logger, int?tableSize, int?bucketSize, TimeSpan?requestTimeout = null) { _transport = transport; _appProtocolVersion = appProtocolVersion; _trustedAppProtocolVersionSigners = trustedAppProtocolVersionSigners; _differentAppProtocolVersionEncountered = differentAppProtocolVersionEncountered; _logger = logger; _address = address; _random = new System.Random(); _tableSize = tableSize ?? Kademlia.TableSize; _bucketSize = bucketSize ?? Kademlia.BucketSize; _routing = new RoutingTable(_address, _tableSize, _bucketSize, _random, _logger); _requestTimeout = requestTimeout ?? TimeSpan.FromMilliseconds(Kademlia.IdleRequestTimeout); }
private Swarm <DumbAction> CreateSwarm( PrivateKey privateKey = null, AppProtocolVersion?appProtocolVersion = null, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, IEnumerable <PublicKey> trustedAppProtocolVersionSigners = null, SwarmOptions options = null, IBlockPolicy <DumbAction> policy = null, Block <DumbAction> genesis = null) { policy = policy ?? new BlockPolicy <DumbAction>(new MinerReward(1)); var fx = new MemoryStoreFixture(policy.BlockAction); var blockchain = MakeBlockChain( policy, fx.Store, fx.StateStore, genesisBlock: genesis ); return(CreateSwarm( blockchain, privateKey, appProtocolVersion, host, listenPort, iceServers, differentAppProtocolVersionEncountered, trustedAppProtocolVersionSigners, options)); }
private Swarm <T> CreateSwarm <T>( BlockChain <T> blockChain, PrivateKey privateKey = null, AppProtocolVersion?appProtocolVersion = null, int?tableSize = null, int?bucketSize = null, string host = null, int?listenPort = null, DateTimeOffset?createdAt = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, IEnumerable <PublicKey> trustedAppProtocolVersionSigners = null ) where T : IAction, new() { if (host is null && !(iceServers?.Any() ?? false)) { host = IPAddress.Loopback.ToString(); } return(new Swarm <T>( blockChain, privateKey ?? new PrivateKey(), appProtocolVersion ?? DefaultAppProtocolVersion, tableSize, bucketSize, 5, host, listenPort, createdAt, iceServers, differentAppProtocolVersionEncountered, trustedAppProtocolVersionSigners)); }
private ITransport CreateTransport( PrivateKey privateKey = null, AppProtocolVersion appProtocolVersion = default, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners = null, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, TimeSpan?messageTimestampBuffer = null ) { if (TransportConstructor is null) { throw new XunitException("Transport constructor is not defined."); } privateKey = privateKey ?? new PrivateKey(); host = host ?? IPAddress.Loopback.ToString(); return(TransportConstructor( privateKey, appProtocolVersion, trustedAppProtocolVersionSigners ?? ImmutableHashSet <PublicKey> .Empty, host, listenPort, iceServers ?? Enumerable.Empty <IceServer>(), differentAppProtocolVersionEncountered, messageTimestampBuffer)); }
private NetMQTransport CreateNetMQTransport( RoutingTable table, PrivateKey privateKey, AppProtocolVersion appProtocolVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, int workers, string host, int?listenPort, IEnumerable <IceServer> iceServers, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered, int minimumBroadcastTarget, TimeSpan?messageLifespan ) { return(new NetMQTransport( table, privateKey, appProtocolVersion, trustedAppProtocolVersionSigners, workers, host, listenPort, iceServers, differentAppProtocolVersionEncountered, minimumBroadcastTarget, messageLifespan)); }
private NetMQTransport CreateNetMQTransport( PrivateKey privateKey = null, int tableSize = 160, int bucketSize = 16, AppProtocolVersion appProtocolVersion = default, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners = null, int workers = 50, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, int minimumBroadcastTarget = 10, TimeSpan?messageLifespan = null ) { privateKey = privateKey ?? new PrivateKey(); host = host ?? IPAddress.Loopback.ToString(); var table = new RoutingTable(privateKey.ToAddress(), tableSize, bucketSize); return(new NetMQTransport( table, privateKey, appProtocolVersion, trustedAppProtocolVersionSigners, workers, host, listenPort, iceServers, differentAppProtocolVersionEncountered, minimumBroadcastTarget, messageLifespan)); }
private ITransport CreateTransport( PrivateKey privateKey = null, int tableSize = 160, int bucketSize = 16, AppProtocolVersion appProtocolVersion = default, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners = null, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, int minimumBroadcastTarget = 10, TimeSpan?messageLifespan = null ) { if (TransportConstructor is null) { throw new XunitException("Transport constructor is not defined."); } privateKey = privateKey ?? new PrivateKey(); host = host ?? IPAddress.Loopback.ToString(); var routingTable = new RoutingTable(privateKey.ToAddress(), tableSize, bucketSize); return(CreateTransport( routingTable, privateKey, appProtocolVersion, trustedAppProtocolVersionSigners ?? ImmutableHashSet <PublicKey> .Empty, host, listenPort, iceServers ?? Enumerable.Empty <IceServer>(), differentAppProtocolVersionEncountered, minimumBroadcastTarget, messageLifespan)); }
private Swarm <T> CreateSwarm <T>( BlockChain <T> blockChain, PrivateKey privateKey = null, AppProtocolVersion?appProtocolVersion = null, string host = null, int?listenPort = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, IEnumerable <PublicKey> trustedAppProtocolVersionSigners = null, SwarmOptions options = null ) where T : IAction, new() { if (host is null && !(iceServers?.Any() ?? false)) { host = IPAddress.Loopback.ToString(); } options ??= new SwarmOptions(); string type = Environment.GetEnvironmentVariable("TRANSPORT_TYPE"); _logger.Debug("Transport type: {Type}", type); switch (type) { case "tcp": options.Type = SwarmOptions.TransportType.TcpTransport; break; case "netmq": options.Type = SwarmOptions.TransportType.NetMQTransport; break; } var swarm = new Swarm <T>( blockChain, privateKey ?? new PrivateKey(), appProtocolVersion ?? DefaultAppProtocolVersion, 5, host, listenPort, iceServers, differentAppProtocolVersionEncountered, trustedAppProtocolVersionSigners, options); _finalizers.Add(async() => { try { await StopAsync(swarm); swarm.Dispose(); } catch (ObjectDisposedException) { _logger.Debug("Swarm {Swarm} is already disposed.", swarm); } }); return(swarm); }
private Swarm <T> CreateSwarm <T>( BlockChain <T> blockChain, PrivateKey privateKey = null, AppProtocolVersion?appProtocolVersion = null, int tableSize = Kademlia.TableSize, int bucketSize = Kademlia.BucketSize, string host = null, int?listenPort = null, DateTimeOffset?createdAt = null, IEnumerable <IceServer> iceServers = null, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered = null, IEnumerable <PublicKey> trustedAppProtocolVersionSigners = null, SwarmOptions options = null ) where T : IAction, new() { if (host is null && !(iceServers?.Any() ?? false)) { host = IPAddress.Loopback.ToString(); } var swarm = new Swarm <T>( blockChain, privateKey ?? new PrivateKey(), appProtocolVersion ?? DefaultAppProtocolVersion, tableSize, bucketSize, 5, host, listenPort, createdAt, iceServers, differentAppProtocolVersionEncountered, trustedAppProtocolVersionSigners, options); _finalizers.Add(async() => { await StopAsync(swarm); swarm.Dispose(); }); return(swarm); }
/// <summary> /// Determines if the peer is compatible with the given criteria. /// </summary> /// <param name="localVersion">The version of the currently running application.</param> /// <param name="trustedSigners">A list of signers to trust. <em>An empty list means /// to trust no one, so that this method always returns <c>false</c>.</em> Conversely, /// <c>null</c> means to <em>trust anyone</em>. Be aware of the difference of those two. /// </param> /// <param name="recognizer">A callback to determine an encountered peer's /// <see cref="AppProtocolVersion"/> is compatible with the currently running /// application, in the case of the peer's version signature is trustworthy but its /// version number is not the same.</param> /// <returns><c>true</c> if the peer is compatible with the given criteria. /// Otherwise <c>false</c>.</returns> public bool IsCompatibleWith( AppProtocolVersion localVersion, IEnumerable <PublicKey> trustedSigners = null, DifferentAppProtocolVersionEncountered recognizer = null ) { if (AppProtocolVersion.Equals(localVersion)) { return(true); } if (trustedSigners is null || trustedSigners.Any(s => AppProtocolVersion.Verify(s))) { return(recognizer is null ? false : recognizer(this, AppProtocolVersion, localVersion)); } return(false); }
public static Message Parse( NetMQMessage raw, bool reply, AppProtocolVersion localVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered) { if (raw.FrameCount == 0) { throw new ArgumentException("Can't parse empty NetMQMessage."); } // (reply == true) [version, type, peer, sign, frames...] // (reply == false) [identity, version, type, peer, sign, frames...] NetMQFrame[] remains = reply ? raw.ToArray() : raw.Skip(1).ToArray(); var versionToken = remains[(int)MessageFrame.Version].ConvertToString(); AppProtocolVersion remoteVersion = AppProtocolVersion.FromToken(versionToken); Peer remotePeer = null; try { remotePeer = DeserializePeer(remains[(int)MessageFrame.Peer].ToByteArray()); } catch (Exception) { // If failed to find out remotePeer, leave it null. } if (!IsAppProtocolVersionValid( remotePeer, localVersion, remoteVersion, trustedAppProtocolVersionSigners, differentAppProtocolVersionEncountered)) { throw new DifferentAppProtocolVersionException( "Received message's version is not valid.", reply ? null : raw[0].Buffer.ToArray(), localVersion, remoteVersion); } var rawType = (MessageType)remains[(int)MessageFrame.Type].ConvertToInt32(); var peer = remains[(int)MessageFrame.Peer].ToByteArray(); byte[] signature = remains[(int)MessageFrame.Sign].ToByteArray(); NetMQFrame[] body = remains.Skip(CommonFrames).ToArray(); // FIXME: The below code is too repetitive and prone to miss to add, which means, // when you add a new message type, you adds an enum member to MessageType and // a corresponding subclass of Message, but misses to add that correspondence here, // you may take a long time to be aware you've missed here, because the code is still // built well and it looks like just Swarm<T> silently ignore new messages. // At least this correspondence map should not be here. var types = new Dictionary <MessageType, Type> { { MessageType.Ping, typeof(Ping) }, { MessageType.Pong, typeof(Pong) }, { MessageType.GetBlockHashes, typeof(GetBlockHashes) }, { MessageType.BlockHashes, typeof(BlockHashes) }, { MessageType.TxIds, typeof(TxIds) }, { MessageType.GetBlocks, typeof(GetBlocks) }, { MessageType.GetTxs, typeof(GetTxs) }, { MessageType.Blocks, typeof(Blocks) }, { MessageType.Tx, typeof(Tx) }, { MessageType.FindNeighbors, typeof(FindNeighbors) }, { MessageType.Neighbors, typeof(Neighbors) }, { MessageType.GetRecentStates, typeof(GetRecentStates) }, { MessageType.RecentStates, typeof(RecentStates) }, { MessageType.BlockHeaderMessage, typeof(BlockHeaderMessage) }, { MessageType.GetChainStatus, typeof(GetChainStatus) }, { MessageType.ChainStatus, typeof(ChainStatus) }, { MessageType.GetBlockStates, typeof(GetBlockStates) }, { MessageType.BlockStates, typeof(BlockStates) }, { MessageType.DifferentVersion, typeof(DifferentVersion) }, }; if (!types.TryGetValue(rawType, out Type type)) { throw new InvalidMessageException( $"Can't determine NetMQMessage. [type: {rawType}]"); } var message = (Message)Activator.CreateInstance( type, new[] { body }); message.Version = remoteVersion; message.Remote = remotePeer; if (!message.Remote.PublicKey.Verify(body.ToByteArray(), signature)) { throw new InvalidMessageException( "The message signature is invalid" ); } if (!reply) { message.Identity = raw[0].Buffer.ToArray(); } return(message); }
public NetMQTransport( PrivateKey privateKey, AppProtocolVersion appProtocolVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, int workers, string host, int?listenPort, IEnumerable <IceServer> iceServers, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered, TimeSpan?messageTimestampBuffer = null) { _logger = Log .ForContext <NetMQTransport>() .ForContext("Source", nameof(NetMQTransport)); if (host is null && (iceServers is null || !iceServers.Any())) { throw new ArgumentException( $"Swarm requires either {nameof(host)} or {nameof(iceServers)}."); } Running = false; _socketCount = 0; _privateKey = privateKey; _host = host; _iceServers = iceServers?.ToList(); _listenPort = listenPort ?? 0; _messageCodec = new NetMQMessageCodec( appProtocolVersion, trustedAppProtocolVersionSigners, differentAppProtocolVersionEncountered, messageTimestampBuffer); _requests = Channel.CreateUnbounded <MessageRequest>(); _runtimeProcessorCancellationTokenSource = new CancellationTokenSource(); _runtimeCancellationTokenSource = new CancellationTokenSource(); _turnCancellationTokenSource = new CancellationTokenSource(); _requestCount = 0; _runtimeProcessor = Task.Factory.StartNew( () => { // Ignore NetMQ related exceptions during NetMQRuntime.Dispose() to stabilize // tests try { using var runtime = new NetMQRuntime(); Task[] workerTasks = Enumerable .Range(0, workers) .Select(_ => ProcessRuntime(_runtimeProcessorCancellationTokenSource.Token)) .ToArray(); runtime.Run(workerTasks); } catch (Exception e) when(e is NetMQException nme || e is ObjectDisposedException ode) { _logger.Error( e, "An exception has occurred while running {TaskName}.", nameof(_runtimeProcessor)); } }, CancellationToken.None, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, TaskScheduler.Default ); ProcessMessageHandler = new AsyncDelegate <Message>(); _replyCompletionSources = new ConcurrentDictionary <string, TaskCompletionSource <object> >(); }