Пример #1
0
        public void TestCommitBlock()
        {
            var(_, inbox, outbox, chainController, c5, _) = TestOpenBlock();

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

            var request = CommitBlockRequest.From(
                _r1, c5, _4_2.ConvertToBlockHandle(c5.Mask), GetMockBlockId(42));

            inbox.TryWrite(request.Span);

            chainController.HandleRequest();

            outbox.Next();
            var result = new CommitBlockResponse(outbox.Peek().Span);

            Assert.Equal(MessageKind.CommitBlockResponse, result.MessageHeader.MessageKind);

            Assert.Equal(_r1, result.MessageHeader.RequestId);
            Assert.Equal(c5, result.MessageHeader.ClientId);

            // TODO: [vermorel] persistence unit tests should be isolated
            //var persister = new BlockchainPersister(TerabConfiguration.CommittedBlocksPersistencePath,
            //    TerabConfiguration.UncommittedBlocksPersistencePath);
            //var newChain = persister.ReadBlockchain();
            //Assert.True(chain.GetLastCommitted().BlockId.Equals(newChain.GetLastCommitted().BlockId));
        }
Пример #2
0
        private static void CommitBlock(BlockHandle handle, CommittedBlockId blockId, ISocketLike socket)
        {
            var request = CommitBlockRequest.From(
                RequestId.MinRequestId, ClientId.MinClientId, handle, blockId);

            socket.Send(request.Span);

            var response = new CommitBlockResponse(new byte[CommitBlockResponse.SizeInBytes]);

            socket.Receive(response.Span);

            if (response.Status != CommitBlockStatus.Success)
            {
                throw new InvalidOperationException("Failed to commit block.");
            }
        }
Пример #3
0
        private static void EnsureGenesisExists(ISocketLike socket)
        {
            var openGenesisRequest = OpenBlockRequest.ForGenesis(RequestId.MinRequestId);

            socket.Send(openGenesisRequest.Span);

            var openGenesisResponse = new OpenBlockResponse(new byte[OpenBlockResponse.SizeInBytes]);

            socket.Receive(openGenesisResponse.Span);

            if (openGenesisResponse.Status == OpenBlockStatus.Success)
            {
                var commitGenesisRequest = CommitBlockRequest.From(
                    RequestId.MinRequestId, ClientId.MinClientId, openGenesisResponse.Handle, CommittedBlockId.Genesis);
                socket.Send(commitGenesisRequest.Span);

                var commitGenesisResponse = new CommitBlockResponse(new byte[CommitBlockResponse.SizeInBytes]);
                socket.Receive(commitGenesisResponse.Span);
            }
        }
Пример #4
0
        public unsafe void OpenCommit()
        {
            var instance = GetInstance();

            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);

                // Commit block
                var blockId = new CommittedBlockId();
                for (var i = 0; i < CommittedBlockId.SizeInBytes; i++)
                {
                    blockId.Data[i] = (byte)i;
                }

                var commitBlockRequest = CommitBlockRequest.From(
                    RequestId.MinRequestId,
                    ClientId.MinClientId,
                    openBlockResponse.Handle,
                    blockId);
                socket.Send(commitBlockRequest.Span);

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

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

                // Get block info
                var getBlockInfoRequest = GetBlockInfoRequest.From(
                    RequestId.MinRequestId,
                    ClientId.MinClientId,
                    openBlockResponse.Handle);
                socket.Send(getBlockInfoRequest.Span);

                var getBlockInfoResponse =
                    new GetBlockInfoResponse(new byte[GetBlockInfoResponse.SizeInBytes]);
                socket.Receive(getBlockInfoResponse.Span);

                Assert.True(getBlockInfoResponse.CommittedBlockId.Equals(blockId));
            }
            finally
            {
                socket.Close();
                instance.Stop();
            }
        }
Пример #5
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();
            }
        }