Example #1
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);
        }
Example #2
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));
        }
Example #3
0
        public void WriteReadCoins()
        {
            var instance = GetInstance();

            var clientId = new ClientId(123);

            instance.Listener.GetNextClientId = () => clientId;

            instance.Start();

            var localEndpoint = new IPEndPoint(IPAddress.Loopback, instance.Port);
            var rawSocket     = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            rawSocket.Connect(localEndpoint);

            var socket = new SocketLikeAdapter(rawSocket);

            try
            {
                // Open block
                var openBlockRequest = OpenBlockRequest.ForGenesis(RequestId.MinRequestId);
                socket.Send(openBlockRequest.Span);

                var openBlockResponse = new OpenBlockResponse(new byte[OpenBlockResponse.SizeInBytes]);
                socket.Receive(openBlockResponse.Span);

                Assert.Equal(OpenBlockStatus.Success, openBlockResponse.Status);

                var reqNum = 0U;

                // Write 100 coins into this open block and save the outpoints to read them later
                var outpointSaverComm         = new Outpoint[100];
                var randyRandom               = new Random(42);
                var produceCoinResponseBuffer = new byte[ProduceCoinResponse.SizeInBytes];
                var consumeCoinResponseBuffer = new byte[ConsumeCoinResponse.SizeInBytes];
                for (var i = 0; i < 100; i++)
                {
                    var coinToWrite = GetCoin(randyRandom, openBlockResponse.Handle.ConvertToBlockAlias(clientId.Mask));

                    outpointSaverComm[i] = coinToWrite.Outpoint;

                    var writeCoinRequest = ProduceCoinRequest.From(
                        new RequestId(++reqNum), clientId, coinToWrite.Outpoint,
                        (OutpointFlags)coinToWrite.OutpointFlags,
                        openBlockResponse.Handle
                        .ConvertToBlockAlias(clientId.Mask),     // reconverted to BlockHandle after object construction
                        coinToWrite.Payload.Satoshis, coinToWrite.Payload.NLockTime,
                        coinToWrite.Payload.Script, clientId.Mask);
                    socket.Send(writeCoinRequest.Span);

                    var writeCoinResponse = new ProduceCoinResponse(produceCoinResponseBuffer);
                    socket.Receive(writeCoinResponse.Span);

                    Assert.Equal(ChangeCoinStatus.Success, writeCoinResponse.Status);

                    // every second coin, write a consumption
                    if (i % 2 == 0)
                    {
                        var writeCoinConsRequest = ConsumeCoinRequest.From(
                            new RequestId(++reqNum), ref coinToWrite.Outpoint,
                            // reconverted to BlockHandle after object construction
                            openBlockResponse.Handle.ConvertToBlockAlias(clientId.Mask),
                            clientId.Mask);
                        socket.Send(writeCoinConsRequest.Span);

                        var consumeCoinResponse = new ConsumeCoinResponse(consumeCoinResponseBuffer);
                        socket.Receive(consumeCoinResponse.Span);

                        Assert.Equal(ChangeCoinStatus.Success, consumeCoinResponse.Status);
                    }
                } // end of write coins

                // Commit the block
                var commitBlockRequest = CommitBlockRequest.From(new RequestId(++reqNum), clientId,
                                                                 openBlockResponse.Handle, CommittedBlockId.Genesis);
                socket.Send(commitBlockRequest.Span);

                var commitBlockResponse = new CommitBlockResponse(new byte[CommitBlockResponse.SizeInBytes]);
                socket.Receive(commitBlockResponse.Span);

                Assert.Equal(CommitBlockStatus.Success, commitBlockResponse.Status);

                // Open a new block
                var openBlockRequest2 =
                    OpenBlockRequest.From(new RequestId(++reqNum), clientId, CommittedBlockId.Genesis);
                socket.Send(openBlockRequest2.Span);

                var openBlockResponse2 = new OpenBlockResponse(new byte[OpenBlockResponse.SizeInBytes]);
                socket.Receive(openBlockResponse2.Span);

                Assert.Equal(OpenBlockStatus.Success, openBlockResponse2.Status);

                // Write 100 coins into the new block
                var outpointSaverUncomm = new Outpoint[100];

                for (var i = 0; i < 100; i++)
                {
                    var coinToWrite = GetCoin(randyRandom,
                                              openBlockResponse2.Handle.ConvertToBlockAlias(clientId.Mask));
                    outpointSaverUncomm[i] = coinToWrite.Outpoint;
                    var writeCoinRequest = ProduceCoinRequest.From(
                        new RequestId(++reqNum), clientId, coinToWrite.Outpoint,
                        (OutpointFlags)coinToWrite.OutpointFlags,
                        openBlockResponse2.Handle
                        .ConvertToBlockAlias(clientId.Mask),     // reconverted to BlockHandle after object construction
                        coinToWrite.Payload.Satoshis, coinToWrite.Payload.NLockTime,
                        coinToWrite.Payload.Script, clientId.Mask);
                    socket.Send(writeCoinRequest.Span);

                    var writeCoinResponse = new ProduceCoinResponse(produceCoinResponseBuffer);
                    socket.Receive(writeCoinResponse.Span);
                    Assert.Equal(ChangeCoinStatus.Success, writeCoinResponse.Status);

                    // every second coin, write a consumption
                    if (i % 2 == 0)
                    {
                        var writeCoinConsRequest = ConsumeCoinRequest.From(
                            new RequestId(++reqNum), ref coinToWrite.Outpoint,
                            openBlockResponse2.Handle
                            .ConvertToBlockAlias(clientId
                                                 .Mask), // reconverted to BlockHandle after object construction
                            clientId.Mask);
                        socket.Send(writeCoinConsRequest.Span);

                        var consumeCoinResponse = new ConsumeCoinResponse(consumeCoinResponseBuffer);
                        socket.Receive(consumeCoinResponse.Span);

                        Assert.Equal(ChangeCoinStatus.Success, consumeCoinResponse.Status);
                    }
                } // end of second write coins

                // Read coins from the committed block
                var headerBuffer = new byte[MessageHeader.SizeInBytes];

                for (var i = 0; i < 100; i++)
                {
                    var readCoinRequest = GetCoinRequest.From(
                        new RequestId(++reqNum), clientId, outpointSaverComm[i],
                        openBlockResponse.Handle.ConvertToBlockAlias(clientId.Mask),
                        clientId.Mask); // reconverted to BlockHandle after object construction
                    socket.Send(readCoinRequest.Span);

                    socket.Receive(headerBuffer);
                    var header = MemoryMarshal.Cast <byte, MessageHeader>(headerBuffer)[0];
                    Assert.Equal(MessageKind.GetCoinResponse, header.MessageKind);
                    var readCoinResponseBuffer = new byte[header.MessageSizeInBytes];
                    headerBuffer.CopyTo(readCoinResponseBuffer, 0);
                    socket.Receive(readCoinResponseBuffer.AsSpan(16));

                    var readCoinResponse = new GetCoinResponse(readCoinResponseBuffer);

                    Assert.Equal(header.MessageSizeInBytes, readCoinResponse.Span.Length);
                    Assert.Equal(openBlockResponse.Handle, readCoinResponse.Production);
                    if (i % 2 == 0)
                    {
                        Assert.Equal(openBlockResponse.Handle.Value, readCoinResponse.Consumption.Value);
                    }
                    else
                    {
                        Assert.Equal(readCoinResponse.Consumption.Value,
                                     BlockAlias.Undefined.ConvertToBlockHandle(clientId.Mask).Value);
                    }

                    Assert.Equal(outpointSaverComm[i], readCoinResponse.Outpoint);
                }

                // Read coins from the uncommitted block
                for (var i = 0; i < 100; i++)
                {
                    var readCoinRequest = GetCoinRequest.From(
                        new RequestId(++reqNum), clientId, outpointSaverUncomm[i],
                        openBlockResponse2.Handle.ConvertToBlockAlias(clientId.Mask),
                        clientId.Mask); // reconverted to BlockHandle after object construction
                    socket.Send(readCoinRequest.Span);

                    socket.Receive(headerBuffer);
                    var header = MemoryMarshal.Cast <byte, MessageHeader>(headerBuffer)[0];
                    Assert.Equal(MessageKind.GetCoinResponse, header.MessageKind);
                    var readCoinResponseBuffer = new byte[header.MessageSizeInBytes];
                    headerBuffer.CopyTo(readCoinResponseBuffer, 0);
                    socket.Receive(readCoinResponseBuffer.AsSpan(16));

                    var readCoinResponse = new GetCoinResponse(readCoinResponseBuffer);

                    Assert.Equal(header.MessageSizeInBytes, readCoinResponse.Span.Length);
                    Assert.Equal(openBlockResponse2.Handle.Value, readCoinResponse.Production.Value);
                    if (i % 2 == 0)
                    {
                        Assert.Equal(openBlockResponse2.Handle.Value, readCoinResponse.Consumption.Value);
                    }
                    else
                    {
                        Assert.Equal(readCoinResponse.Consumption.Value,
                                     BlockAlias.Undefined.ConvertToBlockHandle(clientId.Mask).Value);
                    }

                    Assert.Equal(outpointSaverUncomm[i], readCoinResponse.Outpoint);
                }

                // Read a coin from the future
                var readFutureCoinRequest = GetCoinRequest.From(
                    new RequestId(++reqNum), clientId, outpointSaverUncomm[0],
                    openBlockResponse.Handle.ConvertToBlockAlias(clientId.Mask),
                    clientId.Mask); // reconverted to BlockHandle after object construction
                socket.Send(readFutureCoinRequest.Span);

                socket.Receive(headerBuffer);
                {
                    var header = MemoryMarshal.Cast <byte, MessageHeader>(headerBuffer)[0];
                    var readFutureCoinResponseBuffer = new byte[header.MessageSizeInBytes];
                    var readFutureCoinResponse       = new GetCoinResponse(readFutureCoinResponseBuffer);
                    headerBuffer.CopyTo(readFutureCoinResponseBuffer, 0);
                    socket.Receive(readFutureCoinResponseBuffer.AsSpan(16));

                    Assert.Equal(GetCoinStatus.OutpointNotFound, readFutureCoinResponse.Status);
                }
            }
            finally
            {
                socket.Close();
                instance.Stop();
            }
        }