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>(); }
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); }
public ControllerThread(SimpleBlockchain chain, OptimizedLineage opti, BoundedInbox inbox, BoundedInbox outbox) { _chain = chain; _opti = opti; _inbox = inbox; _outbox = outbox; }
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); }
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(); }
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(); }
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); }
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(); }
// 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); }
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); }
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); }
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(); }
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; }
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)); }
/// <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); }
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. }
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); }
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); }
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; }
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(); }
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()); }
public void SixtyFourInboxes() { new Dispatcher(new ConcurrentQueue <ClientConnection>(), 3, BoundedInbox.Create(), new BoundedInbox[64], BoundedInbox.Create()); }
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(); }
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(); }
public void ZeroInboxes() { Assert.Throws <ArgumentException>(() => new Dispatcher(new ConcurrentQueue <ClientConnection>(), 3, BoundedInbox.Create(), new BoundedInbox[0], BoundedInbox.Create())); }
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(); }
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(); }
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(); } }
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); }
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(); }