Esempio n. 1
0
        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));
        }
Esempio n. 2
0
        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));
        }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        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));
        }
Esempio n. 7
0
        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));
        }
Esempio n. 10
0
        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));
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        /// <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);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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> >();
        }