Пример #1
0
        public DispatchController(
            BoundedInbox inbox,
            BoundedInbox chainControllerBox,
            BoundedInbox[] coinControllerBoxes,
            IOutpointHash hash,
            ILog log = null)
        {
            if (coinControllerBoxes.Length == 0)
            {
                throw new ArgumentException(nameof(coinControllerBoxes));
            }

            _queue = new ConcurrentQueue <ConnectionController>();

            _inbox = inbox;

            _chainControllerBox  = chainControllerBox;
            _coinControllerBoxes = coinControllerBoxes;
            _hash = hash;
            _log  = log;

            _mre = new ManualResetEvent(false);

            OnCoinMessageDispatched = new Action[_coinControllerBoxes.Length];

            _connections = new Dictionary <ClientId, ConnectionController>();
        }
Пример #2
0
        public void TestOpenFirstBlock()
        {
            _controller = new ControllerThread(_chain, default(OptimizedLineage), _inbox = BoundedInbox.Create(),
                                               _outbox = BoundedInbox.Create());

            var messageAllocation = new Span <byte>(new byte[OpenBlock.SizeInBytes]);

            var openBlock = new OpenBlock(1, 5, BlockAlias.GenesisParent);

            // Serialize message to put it into the inbox
            MessageSerializers.ClientSerializeOpenBlock(openBlock, messageAllocation);

            _inbox.TryWrite(messageAllocation);

            _controller.DoWork();

            var result = _outbox.Peek();

            Assert.Equal(MessageType.OpenedBlock, ClientServerMessage.GetMessageType(result));
            var response = MessageSerializers.ClientDeserializeOpenedBlock(result);

            Assert.Equal(1U, response.RequestId);
            Assert.Equal(5U, response.ClientId);
            Assert.Equal(_1, response.Alias);

            var tmpId = response.UncommittedBlockId;

            Console.WriteLine(tmpId);
        }
Пример #3
0
 public ControllerThread(SimpleBlockchain chain, OptimizedLineage opti, BoundedInbox inbox, BoundedInbox outbox)
 {
     _chain  = chain;
     _opti   = opti;
     _inbox  = inbox;
     _outbox = outbox;
 }
Пример #4
0
        public void TryWriteCoinEmptyPayload()
        {
            var sozu = new VolatileCoinStore();

            var inbox      = new BoundedInbox();
            var outbox     = new BoundedInbox();
            var controller = new CoinController(inbox, outbox, sozu, _hash);

            controller.Lineage = MakeLineage();

            var clientId = new ClientId();
            var reqId    = new RequestId(1);

            var coin = GetCoin(_rand);

            var writeCoinRequest = ProduceCoinRequest.From(reqId, clientId, coin.Outpoint,
                                                           (OutpointFlags)coin.OutpointFlags,
                                                           new BlockAlias(3), 100, 50, Span <byte> .Empty, clientId.Mask);

            inbox.TryWrite(writeCoinRequest.Span);
            controller.HandleRequest();

            var raw = outbox.Peek();

            Assert.Equal(ProduceCoinResponse.SizeInBytes, raw.Length);
            var response = new ProduceCoinResponse(raw.Span);

            // verify response contents
            Assert.Equal(reqId, response.MessageHeader.RequestId);
            Assert.Equal(clientId, response.MessageHeader.ClientId);
            Assert.Equal(MessageKind.ProduceCoinResponse, response.MessageHeader.MessageKind);
            Assert.Equal(ChangeCoinStatus.InvalidContext, response.Status);
        }
Пример #5
0
        public void RemoveDeadClients()
        {
            var socket          = new MockSocket();
            var dispatcherInbox = new BoundedInbox();
            var client          = new ConnectionController(dispatcherInbox, socket, ClientId.Next());

            client.OnRequestReceived = () => { };

            socket.ExpectConnected(() => false);

            var dispatcher = new DispatchController(dispatcherInbox, new BoundedInbox(), new BoundedInbox[4],
                                                    new IdentityHash());

            dispatcher.OnConnectionAccepted = (_) => { };
            dispatcher.AddConnection(client);
            dispatcher.HandleNewConnection();

            var firstMessage = new byte[100];
            var message      = new Message(firstMessage);

            message.Header.ClientId           = client.ClientId;
            message.Header.MessageSizeInBytes = 100;
            message.Header.MessageKind        = MessageKind.CloseConnection;

            Assert.True(dispatcherInbox.TryWrite(firstMessage));

            dispatcher.HandleRequest();

            socket.ExpectAllDone();
        }
Пример #6
0
        public void QueueTooManyClients()
        {
            var queue   = new ConcurrentQueue <ClientConnection>();
            var socket  = new MockSocket();
            var client0 = new ClientConnection(socket, ClientId.Next(), 100);
            var client1 = new ClientConnection(socket, ClientId.Next(), 100);
            var client2 = new ClientConnection(socket, ClientId.Next(), 100);
            var client3 = new ClientConnection(socket, ClientId.Next(), 100);

            socket.ExpectConnected(() => true);
            socket.ExpectSend(data =>
            {
                Console.WriteLine(BitConverter.ToString(data.ToArray()));
                Console.WriteLine(BitConverter.ToString(MessageCreationHelper.NoMoreSpaceForClientsMessage));
                Assert.Equal(MessageCreationHelper.NoMoreSpaceForClientsMessage, data.ToArray());
                return(data.Length);
            });
            socket.ExpectClose();

            var dispatcher = new Dispatcher(queue, 3, BoundedInbox.Create(), new BoundedInbox[64],
                                            BoundedInbox.Create());

            queue.Enqueue(client0);
            queue.Enqueue(client1);
            queue.Enqueue(client2);
            queue.Enqueue(client3);
            dispatcher.DequeueNewClients();

            socket.ExpectAllDone();
        }
Пример #7
0
        public void TryReadingNonExistentCoin()
        {
            var sozu = new VolatileCoinStore();

            var inbox      = new BoundedInbox();
            var outbox     = new BoundedInbox();
            var controller = new CoinController(inbox, outbox, sozu, _hash);

            var clientId = new ClientId();
            var reqId    = new RequestId(1);

            var coin = GetCoin(_rand);

            var readCoinRequest = GetCoinRequest.From(reqId, clientId, coin.Outpoint,
                                                      new BlockAlias(3), clientId.Mask);

            inbox.TryWrite(readCoinRequest.Span);
            controller.HandleRequest();

            var raw      = outbox.Peek();
            var response = new GetCoinResponse(raw.Span);

            // verify response contents
            Assert.Equal(reqId, response.MessageHeader.RequestId);
            Assert.Equal(clientId, response.MessageHeader.ClientId);
            Assert.Equal(GetCoinStatus.OutpointNotFound, response.Status);
        }
Пример #8
0
        public void RemoveDeadClients()
        {
            var queue  = new ConcurrentQueue <ClientConnection>();
            var socket = new MockSocket();
            var client = new ClientConnection(socket, ClientId.Next(), 100);

            // First normal loop
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Second loop where client is disconnected and therefore deleted
            socket.ExpectConnected(() => false);
            // No actions for the third loop which should be empty

            var dispatcher = new Dispatcher(queue, 3, BoundedInbox.Create(), new BoundedInbox[64],
                                            BoundedInbox.Create());

            queue.Enqueue(client);
            dispatcher.DequeueNewClients();
            // Normal listen (nothing happens though)
            dispatcher.ListenToConnections();
            // Client is disconnected
            dispatcher.ListenToConnections();
            // Empty loop
            dispatcher.ListenToConnections();

            socket.ExpectAllDone();
        }
Пример #9
0
        // TODO: [vermorel] the 'CancellationTokenSource' should always be the last argument (convention).

        public Worker(BoundedInbox inbox, BoundedInbox outbox, CancellationTokenSource source, ITxoTable txoTable)
        {
            _inbox    = inbox;
            _outbox   = outbox;
            _source   = source;
            _txoTable = txoTable;
            _task     = new Task(Work, _source.Token, TaskCreationOptions.LongRunning);
        }
Пример #10
0
        public void RemoveProductionAndConsumption()
        {
            var sozu = new VolatileCoinStore();

            var inbox      = new BoundedInbox();
            var outbox     = new BoundedInbox();
            var controller = new CoinController(inbox, outbox, sozu, _hash);

            controller.Lineage = new MockLineage();

            var clientId = new ClientId();
            var reqId    = new RequestId(1);

            var coin = GetCoin(_rand);

            sozu.AddProduction(
                _hash.Hash(ref coin.Outpoint),
                ref coin.Outpoint,
                false, coin.Payload,
                new BlockAlias(2),
                null);

            sozu.AddConsumption(
                _hash.Hash(ref coin.Outpoint),
                ref coin.Outpoint,
                new BlockAlias(2),
                null);

            var buffer            = new byte[RemoveCoinRequest.SizeInBytes];
            var removeCoinRequest = new RemoveCoinRequest(
                buffer, reqId, ref coin.Outpoint, new BlockAlias(2).ConvertToBlockHandle(clientId.Mask), true, true);

            inbox.TryWrite(removeCoinRequest.Span);
            controller.HandleRequest();

            var raw = outbox.Peek();

            Assert.Equal(RemoveCoinResponse.SizeInBytes, raw.Length);
            var response = new RemoveCoinResponse(raw.Span);

            // verify response contents
            Assert.Equal(reqId, response.MessageHeader.RequestId);
            Assert.Equal(clientId, response.MessageHeader.ClientId);
            Assert.Equal(MessageKind.RemoveCoinResponse, response.MessageHeader.MessageKind);
            Assert.Equal(ChangeCoinStatus.Success, response.Status);

            sozu.TryGet(_hash.Hash(ref coin.Outpoint), ref coin.Outpoint, new BlockAlias(2), null, out var coin2,
                        out var pe, out var ce);

            Assert.False(pe.IsDefined);
            Assert.False(ce.IsDefined);
        }
Пример #11
0
        public CoinController(BoundedInbox inbox, BoundedInbox outbox, ICoinStore store, IOutpointHash hash,
                              ILog log = null, int shardIndex = -1)
        {
            _inbox      = inbox;
            _outbox     = outbox;
            _store      = store;
            _hash       = hash;
            _log        = log;
            _shardIndex = shardIndex;

            _pool = new SpanPool <byte>(PoolSizeInBytes);
            _mre  = new ManualResetEvent(false);
        }
Пример #12
0
        public ChainController(IChainStore store, BoundedInbox inbox, BoundedInbox outbox,
                               Action <ILineage> propagateLineage, ILog log = null)
        {
            _store            = store;
            _inbox            = inbox;
            _outbox           = outbox;
            _propagateLineage = propagateLineage;
            _log = log;

            _pool = new SpanPool <byte>(GetBlockInfoResponse.SizeInBytes);
            _mre  = new ManualResetEvent(false);

            RefreshAndPropagateLineage();
        }
Пример #13
0
 public ConnectionController(BoundedInbox dispatchInbox, ISocketLike socket, ClientId clientId, ILog log = null)
 {
     _dispatchInbox       = dispatchInbox ?? throw new ArgumentNullException(nameof(dispatchInbox));
     _outbox              = new BoundedInbox(Constants.ConnectionControllerOutboxSize);
     _socket              = socket ?? throw new ArgumentNullException(nameof(socket));
     _clientId            = clientId;
     _log                 = log;
     _bufferIn            = new byte[Constants.MaxRequestSize];
     _mre                 = new ManualResetEvent(false);
     _tokenSource         = new CancellationTokenSource();
     _requestsInProgress  = 0;
     _responsePool        = new SpanPool <byte>(ResponsePoolSize);
     _responseCountInPool = 0;
 }
Пример #14
0
        public void ReadExistingCoin()
        {
            var sozu = new VolatileCoinStore();

            var inbox      = new BoundedInbox();
            var outbox     = new BoundedInbox();
            var controller = new CoinController(inbox, outbox, sozu, _hash);

            var coin = GetCoin(_rand);

            sozu.AddProduction(
                _hash.Hash(ref coin.Outpoint),
                ref coin.Outpoint,
                false, coin.Payload,
                new BlockAlias(3),
                null); // lineage is not used in VolatileCoinStore

            var clientId = new ClientId();
            var reqId    = new RequestId(1);

            var context = new BlockAlias(3);

            var readCoinRequest = GetCoinRequest.From(reqId, clientId, coin.Outpoint, context, clientId.Mask);

            inbox.TryWrite(readCoinRequest.Span);
            controller.HandleRequest();

            var raw      = outbox.Peek();
            var response = new GetCoinResponse(raw.Span);

            Assert.Equal(response.MessageHeader.MessageSizeInBytes, raw.Length);

            // verify response contents
            Assert.Equal(reqId, response.MessageHeader.RequestId);
            Assert.Equal(clientId, response.MessageHeader.ClientId);
            Assert.Equal(MessageKind.GetCoinResponse, response.MessageHeader.MessageKind);
            Assert.Equal(coin.Outpoint, response.Outpoint);
            Assert.Equal(OutpointFlags.None, response.OutpointFlags);
            Assert.Equal(context, response.Context.ConvertToBlockAlias(clientId.Mask));
            Assert.Equal(context, response.Production.ConvertToBlockAlias(clientId.Mask));
            Assert.Equal(BlockAlias.Undefined.ConvertToBlockHandle(clientId.Mask), response.Consumption);
            Assert.Equal(coin.Payload.Satoshis, response.Satoshis);
            Assert.Equal(coin.Payload.NLockTime, response.NLockTime);
            Assert.True(coin.Payload.Script.SequenceEqual(response.Script));
        }
Пример #15
0
        /// <remarks>
        /// A port at zero indicates to chose any available port.
        /// </remarks>
        public Listener(
            BoundedInbox dispatchInbox,
            IPAddress ipAddress,
            int port,
            ILog log = null)
        {
            _dispatchInbox = dispatchInbox;
            _log           = log;

            var localEndPoint = new IPEndPoint(ipAddress, port);

            _socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _socket.Bind(localEndPoint);

            Port = ((IPEndPoint)_socket.LocalEndPoint).Port;

            _socket.Listen(Constants.SocketReceiveBufferSize);
        }
Пример #16
0
        public void Setup()
        {
            var sharedInboxDispatcherController  = BoundedInbox.Create();
            var sharedOutboxDispatcherController = BoundedInbox.Create();
            var clientQueue = new ConcurrentQueue <ClientConnection>();

            _dispatcher = new Dispatcher(clientQueue, 3, sharedOutboxDispatcherController, new BoundedInbox[4],
                                         sharedInboxDispatcherController);
            _chain            = new SimpleBlockchain();
            _controllerThread = new ControllerThread(_chain, default(OptimizedLineage), sharedInboxDispatcherController,
                                                     sharedOutboxDispatcherController);
            _clientConn = new ClientConnection(_socket, ClientId.Next(), ClientServerMessage.MaxSizeInBytes);

            clientQueue.Enqueue(_clientConn);
            _dispatcher.DequeueNewClients();

            // TODO there should really be three threads, one for each component. However, I do not know how to test this.
        }
Пример #17
0
        public void Setup()
        {
            var dispatchInbox = new BoundedInbox();
            var chainInbox    = new BoundedInbox();
            var coinInboxes   = new BoundedInbox[ShardCount];

            for (var i = 0; i < coinInboxes.Length; i++)
            {
                coinInboxes[i] = new BoundedInbox();
            }

            _dispatcher = new DispatchController(
                dispatchInbox,
                chainInbox,
                coinInboxes,
                new IdentityHash());

            // Configure the wake-up callbacks to do nothing.
            _dispatcher.OnBlockMessageDispatched = () => { };
            for (var i = 0; i < _dispatcher.OnCoinMessageDispatched.Length; i++)
            {
                _dispatcher.OnCoinMessageDispatched[i] = () => { }
            }
            ;

            _store = new VolatileChainStore();

            _chainController = new ChainController(
                _store,
                chainInbox,
                dispatchInbox,
                lineage => { });

            var c1 = ClientId.Next();

            _clientConn = new ConnectionController(dispatchInbox, _socket, c1);
            _handleMask = c1.Mask;

            _dispatcher.AddConnection(_clientConn);
            _dispatcher.OnConnectionAccepted = _ => { };
            _dispatcher.HandleNewConnection();

            _c0 = new ClientId(0);
        }
Пример #18
0
        public void WriteCoinCons()
        {
            var sozu = new VolatileCoinStore();

            var inbox      = new BoundedInbox();
            var outbox     = new BoundedInbox();
            var controller = new CoinController(inbox, outbox, sozu, _hash);

            controller.Lineage = new MockLineage();

            var clientId = new ClientId();
            var reqId    = new RequestId(1);

            var coin = GetCoin(_rand);

            sozu.AddProduction(
                _hash.Hash(ref coin.Outpoint),
                ref coin.Outpoint,
                false, coin.Payload,
                new BlockAlias(2),
                null);

            var pool             = new SpanPool <byte>(4096);
            var buffer           = new byte[ConsumeCoinRequest.SizeInBytes];
            var writeCoinRequest = new ConsumeCoinRequest(
                reqId, ref coin.Outpoint, new BlockAlias(2).ConvertToBlockHandle(clientId.Mask), pool);

            inbox.TryWrite(writeCoinRequest.Span);
            controller.HandleRequest();

            var raw = outbox.Peek();

            Assert.Equal(ConsumeCoinResponse.SizeInBytes, raw.Length);
            var response = new ConsumeCoinResponse(raw.Span);

            // verify response contents
            Assert.Equal(reqId, response.MessageHeader.RequestId);
            Assert.Equal(clientId, response.MessageHeader.ClientId);
            Assert.Equal(MessageKind.ConsumeCoinResponse, response.MessageHeader.MessageKind);
            Assert.Equal(ChangeCoinStatus.Success, response.Status);
        }
Пример #19
0
        public Dispatcher(
            ConcurrentQueue <ClientConnection> queue,
            uint maxClientNumber,
            BoundedInbox outbox,
            BoundedInbox[] workerInboxes,
            BoundedInbox controllerInbox)
        {
            // TODO: [vermorel] Isolate power-of-2 check as a 'Math' extension and unit-test accordingly.

            // verify that the number of inboxes is a power of 2
            if (workerInboxes.Length == 0 || Math.Log(workerInboxes.Length, 2) % 1 != 0)
            {
                throw new ArgumentException(
                          $"The number of sharded inboxes is {workerInboxes.Length}. Should be a power of 2.");
            }

            _queue           = queue;
            _maxClientNumber = maxClientNumber;

            _outbox          = outbox;
            _workerInboxes   = workerInboxes;
            _controllerInbox = controllerInbox;
        }
Пример #20
0
        public void QueueTooManyClients()
        {
            var socket          = new MockSocket();
            var dispatcherInbox = new BoundedInbox();
            var dispatcher      = new DispatchController(dispatcherInbox, new BoundedInbox(), new BoundedInbox[64],
                                                         new IdentityHash());

            dispatcher.OnConnectionAccepted = (_) => { };

            for (var i = 0; i < Constants.MaxActiveConnections; i++)
            {
                var client0 = new ConnectionController(dispatcherInbox, socket, ClientId.Next());
                client0.OnRequestReceived = () => { };
                dispatcher.AddConnection(client0);
                dispatcher.HandleNewConnection();
            }

            var client1 = new ConnectionController(dispatcherInbox, socket, ClientId.Next());

            client1.OnRequestReceived = () => { };

            socket.ExpectSend(data =>
            {
                Assert.Equal(ProtocolErrorResponse.SizeInBytes, data.Length);

                var errorMessage = new ProtocolErrorResponse(data);
                Assert.Equal(MessageKind.ProtocolErrorResponse, errorMessage.MessageHeader.MessageKind);
                Assert.Equal(ProtocolErrorStatus.TooManyActiveClients, errorMessage.Status);

                return(data.Length);
            });

            dispatcher.AddConnection(client1);
            dispatcher.HandleNewConnection();
            client1.HandleResponse();
            socket.ExpectAllDone();
        }
Пример #21
0
        public void Setup()
        {
            var id = _chain.OpenFirstBlock().Alias;

            _chain.CommitBlock(id, BlockId.Genesis);

            id = _chain.OpenBlock(_1).Alias;
            _chain.CommitBlock(id, new BlockId(new Hash256(0x11111111UL, 0x22222222UL, 0x33333333UL, 0x44444444UL)));
            id = _chain.OpenBlock(_2).Alias;
            _chain.CommitBlock(id, new BlockId(new Hash256(0xFFFFFFFFUL, 0xEEEEEEEEUL, 0xDDDDDDDDUL, 0xCCCCCCCCUL)));
            // Second child for block 2
            id = _chain.OpenBlock(_2).Alias;
            _chain.CommitBlock(id,
                               new BlockId(new Hash256(0x1111111122UL, 0x2222222233UL, 0x3333333344UL, 0x4444444455UL)));
            // main chain prolonged
            id = _chain.OpenBlock(_3).Alias;
            _chain.CommitBlock(id,
                               new BlockId(new Hash256(0x1111111122UL, 0x2222222233UL, 0x3333333344UL, 0x4444444455UL)));
            // side chain prolonged
            id = _chain.OpenBlock(_4).Alias;
            _chain.CommitBlock(id,
                               new BlockId(new Hash256(0x1111111122UL, 0x2222222233UL, 0x3333333344UL, 0x4444444455UL)));
            // fork on end of main chain
            id = _chain.OpenBlock(_5).Alias;
            _chain.CommitBlock(id,
                               new BlockId(new Hash256(0x1111111122UL, 0x2222222233UL, 0x3333333344UL, 0x4444444455UL)));
            id = _chain.OpenBlock(_5).Alias;
            _chain.CommitBlock(id,
                               new BlockId(new Hash256(0x1111111122UL, 0x2222222233UL, 0x3333333344UL, 0x4444444455UL)));

            var chainStrategy = new BlockchainStrategies();
            var opti          = new OptimizedLineage(chainStrategy.GetQuasiOrphans(_chain), _2);

            _controller = new ControllerThread(_chain, opti, _inbox = BoundedInbox.Create(),
                                               _outbox = BoundedInbox.Create());
        }
Пример #22
0
 public void SixtyFourInboxes()
 {
     new Dispatcher(new ConcurrentQueue <ClientConnection>(), 3, BoundedInbox.Create(), new BoundedInbox[64],
                    BoundedInbox.Create());
 }
Пример #23
0
        public void ReadMultipleMessagesFromClient()
        {
            var queue   = new ConcurrentQueue <ClientConnection>();
            var socket  = new MockSocket();
            var client1 = new ClientConnection(socket, ClientId.Next(), 100);
            var client2 = new ClientConnection(socket, ClientId.Next(), 100);

            var dispatcher = new Dispatcher(queue, 3, BoundedInbox.Create(),
                                            new BoundedInbox[2], BoundedInbox.Create());

            // Client1 messages
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 600);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                // Three messages, of sizes 200, 300 and 100
                BitConverter.GetBytes(200).CopyTo(data);
                BitConverter.GetBytes(300).CopyTo(data.Slice(200));
                BitConverter.GetBytes(100).CopyTo(data.Slice(500));
                return(600);
            });
            // Reading second message
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Reading third message
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Exiting loop
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client2 messages
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 100);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(70).CopyTo(data);
                BitConverter.GetBytes(30).CopyTo(data.Slice(70));
                return(100);
            });
            // Reading second message
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Exiting loop
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Some more messages for Client1
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 60);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                // Two messages, of sizes 10 and 40
                BitConverter.GetBytes(25).CopyTo(data);
                BitConverter.GetBytes(35).CopyTo(data.Slice(25));
                return(60);
            });
            // Reading second message
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Exiting loop
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // No more messages for Client2
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            queue.Enqueue(client1);
            queue.Enqueue(client2);
            dispatcher.DequeueNewClients();
            // Client1 reading 3 messages, Client2 two
            dispatcher.ListenToConnections();
            // Client1 reading 2 more messages, Client2 none
            dispatcher.ListenToConnections();

            socket.ExpectAllDone();
        }
Пример #24
0
        public void SendAnswers()
        {
            var queue   = new ConcurrentQueue <ClientConnection>();
            var socket  = new MockSocket();
            var outbox  = BoundedInbox.Create();
            var client1 = new ClientConnection(socket, ClientId.Next(), 100);
            var client2 = new ClientConnection(socket, ClientId.Next(), 100);

            queue.Enqueue(client1);
            queue.Enqueue(client2);

            var dispatcher = new Dispatcher(queue, 3, outbox,
                                            new BoundedInbox[2], BoundedInbox.Create());

            // Try sending message to one client, doesn't succeed
            socket.ExpectConnected(() => true);
            socket.ExpectSend(data => 0);
            // Try sending message to the other client, doesn't succeed
            socket.ExpectConnected(() => true);
            socket.ExpectSend(data => 0);
            // Try sending message to first client, socket gets closed
            socket.ExpectConnected(() => true);
            socket.ExpectClose();
            // Try sending message to second client, socket gets closed
            socket.ExpectConnected(() => true);
            socket.ExpectClose();

            var firstMessage = new byte[100];

            BitConverter.GetBytes(100).CopyTo(new Span <byte>(firstMessage));
            client2.ConnectionId.WriteTo(  // send back to client2
                firstMessage.AsSpan(ClientServerMessage.ClientIdStart, ClientServerMessage.ClientIdSizeInBytes));

            var secondMessage = new byte[100];

            BitConverter.GetBytes(100).CopyTo(new Span <byte>(secondMessage));
            client1.ConnectionId.WriteTo( // send back to client1
                secondMessage.AsSpan(ClientServerMessage.ClientIdStart, ClientServerMessage.ClientIdSizeInBytes));

            var thirdMessage = new byte[50];

            BitConverter.GetBytes(50).CopyTo(new Span <byte>(thirdMessage));
            client1.ConnectionId.WriteTo( // send back to client1
                thirdMessage.AsSpan(ClientServerMessage.ClientIdStart, ClientServerMessage.ClientIdSizeInBytes));

            var fourthMessage = new byte[50];

            BitConverter.GetBytes(50).CopyTo(new Span <byte>(fourthMessage));
            client2.ConnectionId.WriteTo( // send back to client2
                fourthMessage.AsSpan(ClientServerMessage.ClientIdStart, ClientServerMessage.ClientIdSizeInBytes));

            // Write messages into dispatcher buffer for both clients
            Assert.True(outbox.TryWrite(firstMessage));
            Assert.True(outbox.TryWrite(secondMessage));
            dispatcher.DequeueNewClients();
            // Try sending the answers, fails
            dispatcher.SendResponses();

            Assert.True(outbox.TryWrite(thirdMessage));
            Assert.True(outbox.TryWrite(fourthMessage));
            dispatcher.SendResponses();

            socket.ExpectAllDone();
        }
Пример #25
0
 public void ZeroInboxes()
 {
     Assert.Throws <ArgumentException>(() =>
                                       new Dispatcher(new ConcurrentQueue <ClientConnection>(), 3, BoundedInbox.Create(), new BoundedInbox[0],
                                                      BoundedInbox.Create()));
 }
Пример #26
0
        public void FillShardedInboxes()
        {
            var queue   = new ConcurrentQueue <ClientConnection>();
            var socket  = new MockSocket();
            var client1 = new ClientConnection(socket, ClientId.Next(), 100);
            var client2 = new ClientConnection(socket, ClientId.Next(), 100);

            BoundedInbox[] threadInboxes =
            {
                BoundedInbox.Create(), BoundedInbox.Create()
            };

            var dispatcher = new Dispatcher(queue, 3, BoundedInbox.Create(),
                                            threadInboxes, BoundedInbox.Create());

            // Client1 sharded message
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                data[ClientServerMessage.ShardedIndStart] = 0xFF; // 0xFF: all bits set to one, so "sharded" is set to 1 for sure
                data[ClientServerMessage.PayloadStart]    = 0x01;
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client2 sharded message
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                data[12] = 0xFF;
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client1 sharded message, fills up first sharded inbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                data[ClientServerMessage.ShardedIndStart] = 0xFF; // 0xFF: all bits set to one, so "sharded" is set to 1 for sure
                data[ClientServerMessage.PayloadStart]    = 0x00;
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client2 sharded message, fills up second sharded inbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                data[ClientServerMessage.ShardedIndStart] = 0xFF; // 0xFF: all bits set to one, so "sharded" is set to 1 for sure
                data[ClientServerMessage.PayloadStart]    = 0x01;
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Read and get error message server busy writing into second sharded inbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 20);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(20).CopyTo(data);
                data[ClientServerMessage.ShardedIndStart] = 0xFF;
                data[ClientServerMessage.PayloadStart]    = 0x01;
                return(20);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectSend(data =>
            {
                Assert.Equal(ClientServerMessage.PayloadStart, data.Length);
                Assert.Equal(data[13], (byte)MessageType.ServerBusy);
                return(ClientServerMessage.PayloadStart);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Read and get error message server busy writing into first sharded inbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 20);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(20).CopyTo(data);
                data[ClientServerMessage.ShardedIndStart] = 0xFF; // 0xFF: all bits set to one, so "sharded" is set to 1 for sure
                data[ClientServerMessage.PayloadStart]    = 0x00;
                return(20);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectSend(data =>
            {
                Assert.Equal(ClientServerMessage.PayloadStart, data.Length);
                Assert.Equal(MessageType.ServerBusy, ClientServerMessage.GetMessageType(data));
                return(ClientServerMessage.PayloadStart);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            queue.Enqueue(client1);
            queue.Enqueue(client2);
            dispatcher.DequeueNewClients();
            // Client1 into sharded inbox 1, Client2 into sharded inbox 2
            dispatcher.ListenToConnections();
            // Client1 filling up sharded inbox 2, Client2 filling up sharded inbox 1
            dispatcher.ListenToConnections();
            // Errors when trying to write into any inbox
            dispatcher.ListenToConnections();

            socket.ExpectAllDone();
        }
Пример #27
0
        public void FillControllerInbox()
        {
            var queue   = new ConcurrentQueue <ClientConnection>();
            var socket  = new MockSocket();
            var client1 = new ClientConnection(socket, ClientId.Next(), 100);
            var client2 = new ClientConnection(socket, ClientId.Next(), 100);


            // Client1 empty inbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);
            // Client2 unsharded message
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client1 unsharded message, fills up ControllerInbox
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => LargeMessageSize);
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(LargeMessageSize).CopyTo(data);
                return(LargeMessageSize);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            // Client2 unsharded message, gets BufferFull response
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => ClientServerMessage.PayloadStart); // minimal valid message size
            socket.ExpectReceive(data =>
            {
                data.Clear();
                BitConverter.GetBytes(ClientServerMessage.PayloadStart).CopyTo(data);
                return(ClientServerMessage.PayloadStart);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectSend(data =>
            {
                Assert.Equal(ClientServerMessage.PayloadStart, data.Length);
                Assert.Equal(data[13], (int)MessageType.ServerBusy);
                return(ClientServerMessage.PayloadStart);
            });
            socket.ExpectConnected(() => true);
            socket.ExpectAvailable(() => 0);

            var dispatcher = new Dispatcher(queue, 3, BoundedInbox.Create(), new BoundedInbox[64],
                                            BoundedInbox.Create());

            queue.Enqueue(client1);
            queue.Enqueue(client2);
            dispatcher.DequeueNewClients();
            // Client1 empty inbox, Client2 LargeMessageSize bytes unsharded
            dispatcher.ListenToConnections();
            // Client1 LargeMessageSize bytes unsharded, Client2 10 bytes, error message
            dispatcher.ListenToConnections();

            socket.ExpectAllDone();
        }
Пример #28
0
        public void SendAnswers()
        {
            var dispatcherInbox = new BoundedInbox();
            var socket1         = new MockSocket();
            var socket2         = new MockSocket();
            var client1         = new ConnectionController(dispatcherInbox, socket1, ClientId.Next());
            var client2         = new ConnectionController(dispatcherInbox, socket2, ClientId.Next());

            client1.OnRequestReceived = () => { };
            client2.OnRequestReceived = () => { };

            var dispatcher = new DispatchController(dispatcherInbox, new BoundedInbox(), new BoundedInbox[2],
                                                    new IdentityHash());

            // Nil handling of notifications
            dispatcher.OnBlockMessageDispatched = () => { };
            for (var i = 0; i < dispatcher.OnCoinMessageDispatched.Length; i++)
            {
                dispatcher.OnCoinMessageDispatched[i] = () => { }
            }
            ;
            dispatcher.OnConnectionAccepted = (_) => { };


            var firstMessage = new byte[Constants.MaxRequestSize];
            var message      = new Message(firstMessage);

            message.Header.ClientId           = client2.ClientId;
            message.Header.MessageSizeInBytes = Constants.MaxRequestSize;
            message.Header.MessageKind        = MessageKind.GetCoinResponse;


            var secondMessage = new byte[Constants.MaxRequestSize];

            message = new Message(secondMessage);
            message.Header.ClientId           = client1.ClientId;
            message.Header.MessageSizeInBytes = Constants.MaxRequestSize;
            message.Header.MessageKind        = MessageKind.GetCoinResponse;

            var thirdMessage = new byte[50];

            message = new Message(thirdMessage);
            message.Header.ClientId           = client1.ClientId;
            message.Header.MessageSizeInBytes = 50;
            message.Header.MessageKind        = MessageKind.GetCoinResponse;


            var fourthMessage = new byte[50];

            message = new Message(fourthMessage);
            message.Header.ClientId           = client2.ClientId;
            message.Header.MessageSizeInBytes = 50;
            message.Header.MessageKind        = MessageKind.GetCoinResponse;

            dispatcher.AddConnection(client1);
            dispatcher.AddConnection(client2);
            dispatcher.HandleNewConnection();
            dispatcher.HandleNewConnection();


            // Write messages into dispatcher buffer for both clients
            for (var i = 0; i < Constants.SocketSendBufferSize / Constants.MaxRequestSize; i++)
            {
                socket1.ExpectConnected(() => true);
                socket2.ExpectConnected(() => true);

                Assert.True(dispatcherInbox.TryWrite(firstMessage));
                Assert.True(dispatcherInbox.TryWrite(secondMessage));

                // Try sending the answers, fails
                dispatcher.HandleRequest();
                dispatcher.HandleRequest();
            }

            // Try sending message to first client, socket gets closed
            socket1.ExpectConnected(() => true);
            socket1.ExpectClose();
            // Try sending message to second client, socket gets closed
            socket2.ExpectConnected(() => true);
            socket2.ExpectClose();

            Assert.True(dispatcherInbox.TryWrite(thirdMessage));
            Assert.True(dispatcherInbox.TryWrite(fourthMessage));
            dispatcher.HandleRequest();
            dispatcher.HandleRequest();

            socket1.ExpectAllDone();
            socket2.ExpectAllDone();
        }
    }
Пример #29
0
        public (IChainStore, BoundedInbox, BoundedInbox, ChainController, ClientId) Setup(int pruneLimit = 100)
        {
            var store = new VolatileChainStore();

            store.BlockPruneLimitDistance = pruneLimit;

            Assert.Equal(OpenBlockStatus.Success,
                         store.TryOpenBlock(CommittedBlockId.GenesisParent, out var openedBlock));
            var id = openedBlock.Alias;

            Assert.NotEqual(BlockAlias.GenesisParent, id);

            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(id, CommittedBlockId.Genesis, out _));
            // C(0)

            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(CommittedBlockId.Genesis, out var cb1));
            Assert.Equal(_1, cb1.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb1.Alias, _id_1, out _));
            // C(0) -> C(1)

            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_1, out var cb2));
            Assert.Equal(_2, cb2.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb2.Alias, _id_2, out _));
            // C(0) -> C(1) -> C(2)

            // Second child for block 2
            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_1, out var cb3));
            Assert.Equal(_2_1, cb3.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb3.Alias, _id_2_1, out _));
            // C(0) -> C(1) -> C(2)
            //             \-> C(2-1)

            // main chain prolonged
            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_2, out var cb4));
            Assert.Equal(_3, cb4.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb4.Alias, _id_3, out _));
            // C(0) -> C(1) -> C(2)  -> C(3)
            //             \-> C(2-1)

            // side chain prolonged
            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_2_1, out var cb5));
            // the new assert
            Assert.Equal(_3_1, cb5.Alias);
            // the new assert
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb5.Alias, _id_3_1, out _));
            // C(0) -> C(1) -> C(2)   -> C(3)
            //             \-> C(2-1) -> C(3-1)

            // fork on end of main chain
            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_3, out var cb6));
            Assert.Equal(_4_0, cb6.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb6.Alias, _id_4_0, out _));

            Assert.Equal(OpenBlockStatus.Success, store.TryOpenBlock(_id_3, out var cb7));
            Assert.Equal(_4_1, cb7.Alias);
            Assert.Equal(CommitBlockStatus.Success, store.TryCommitBlock(cb7.Alias, _id_4_1, out _));

            // C(0) -> C(1) -> C(2)   -> C(3) -> C(4)
            //             |                 \-> C(4-1)
            //             \-> C(2-1) -> C(3-1)

            var inbox  = new BoundedInbox();
            var outbox = new BoundedInbox();

            var chainController = new ChainController(
                store,
                inbox,
                outbox,
                lineage => { });

            ClientId.Next();
            ClientId.Next();
            ClientId.Next();
            ClientId.Next();
            var c5 = ClientId.Next();

            return(store, inbox, outbox, chainController, c5);
        }
Пример #30
0
        public void FillChainControllerInbox()
        {
            var socket1         = new MockSocket();
            var socket2         = new MockSocket();
            var dispatcherInbox = new BoundedInbox();
            var client1         = new ConnectionController(dispatcherInbox, socket1, ClientId.Next());
            var client2         = new ConnectionController(dispatcherInbox, socket2, ClientId.Next());

            client1.OnRequestReceived = () => { };
            client2.OnRequestReceived = () => { };

            Func <int, int, MockSocket.SpanToInt> func = (s1, s2) =>
            {
                return(data =>
                {
                    data.Clear();
                    BinaryPrimitives.TryWriteInt32LittleEndian(data, s1);
                    // TODO: [vermorel] PingChainController has been removed, logic need to be upgraded.
                    //MessageKind.PingChainController.WriteTo(data.Slice(MessageHeaderHelper.MessageKindStart));
                    return s2;
                });
            };

            socket2.ExpectReceive(func(LargeMessageSize, MessageHeader.SizeInBytes));
            socket2.ExpectReceive(func(LargeMessageSize, LargeMessageSize));
            socket1.ExpectReceive(func(LargeMessageSize, MessageHeader.SizeInBytes));
            socket1.ExpectReceive(func(LargeMessageSize, LargeMessageSize));
            // request too short
            var bodyStart = sizeof(int) + RequestId.SizeInBytes + ClientId.SizeInBytes + sizeof(MessageKind);

            socket2.ExpectReceive(func(bodyStart, bodyStart));


            socket2.ExpectSend(data =>
            {
                Assert.Equal(ProtocolErrorResponse.SizeInBytes, data.Length);
                var message = new ProtocolErrorResponse(data);
                Assert.Equal(MessageKind.ProtocolErrorResponse, message.MessageHeader.MessageKind);
                Assert.Equal(ProtocolErrorStatus.RequestTooShort, message.Status);

                return(ProtocolErrorResponse.SizeInBytes);
            });

            socket2.ExpectConnected(() => true);
            socket1.ExpectConnected(() => true);

            var dispatcher = new DispatchController(dispatcherInbox,
                                                    new BoundedInbox(Constants.MaxResponseSize),
                                                    Enumerable.Range(0, 32).Select(x => new BoundedInbox()).ToArray(),
                                                    new IdentityHash());

            // Nil handling of notifications
            dispatcher.OnBlockMessageDispatched = () => { };
            for (var i = 0; i < dispatcher.OnCoinMessageDispatched.Length; i++)
            {
                dispatcher.OnCoinMessageDispatched[i] = () => { }
            }
            ;

            dispatcher.OnConnectionAccepted = (_) => { };
            dispatcher.AddConnection(client1);
            dispatcher.AddConnection(client2);

            dispatcher.HandleNewConnection();
            dispatcher.HandleNewConnection();
            client1.HandleRequest();
            client2.HandleRequest();
            client2.HandleRequest();
            client2.HandleResponse();
            dispatcher.HandleRequest();
            dispatcher.HandleRequest();
            dispatcher.HandleRequest();

            socket1.ExpectAllDone();
            socket2.ExpectAllDone();
        }