Exemple #1
0
        public void TestOpenFirstBlock()
        {
            var(_, inbox, outbox, _, c5) = Setup();

            var store = new VolatileChainStore();

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

            var request = OpenBlockRequest.From(
                _r1, c5, CommittedBlockId.GenesisParent);

            inbox.TryWrite(request.Span);

            chainController.HandleRequest();

            var result = new OpenBlockResponse(outbox.Peek().Span);

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

            Assert.Equal(_r1, result.MessageHeader.RequestId);
            Assert.Equal(c5, result.MessageHeader.ClientId);
            Assert.Equal(new BlockAlias(0, 0), result.Handle.ConvertToBlockAlias(c5.Mask));

            // TODO: [vermorel] persistence unit tests should be isolated
            //var persister = new BlockchainPersister(TerabConfiguration.CommittedBlocksPersistencePath,
            //    TerabConfiguration.UncommittedBlocksPersistencePath);
            //var newChain = persister.ReadBlockchain();
            //Assert.Equal(chain.UncommittedBlockCount, newChain.UncommittedBlockCount);
            //Assert.Equal(chain.CommittedBlockCount, newChain.CommittedBlockCount);
        }
Exemple #2
0
        public (IChainStore, BoundedInbox, BoundedInbox, ChainController, ClientId, UncommittedBlockId) TestOpenBlock()
        {
            var(store, inbox, outbox, chainController, c5) = Setup();

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

            var request = OpenBlockRequest.From(_r1, c5, _id_3);

            inbox.TryWrite(request.Span);

            chainController.HandleRequest();

            var result = new OpenBlockResponse(outbox.Peek().Span);

            Assert.Equal(MessageKind.OpenBlockResponse, result.MessageHeader.MessageKind);
            Assert.Equal(_r1, result.MessageHeader.RequestId);
            Assert.Equal(c5, result.MessageHeader.ClientId);
            Assert.Equal(_4_2, result.Handle.ConvertToBlockAlias(c5.Mask));

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


            // TODO: [vermorel] Persistence unit tests should be isolated
            //var persister = new BlockchainPersister(TerabConfiguration.CommittedBlocksPersistencePath,
            //    TerabConfiguration.UncommittedBlocksPersistencePath);
            //var newChain = persister.ReadBlockchain();
            //Assert.Equal(chain.UncommittedBlockCount, newChain.UncommittedBlockCount);

            return(store, inbox, outbox, chainController, c5, result.UncommittedBlockId);
        }
Exemple #3
0
        public UncommittedBlockId terab_utxo_open_block()
        {
            Setup();

            UncommittedBlockId?result = null;

            _socket.ExpectReceive(data =>
            {
                data.Clear();
                Assert.True(data.Length == MessageHeader.SizeInBytes);

                var header        = new MessageHeader(OpenBlockRequest.SizeInBytes, _r1, _c0, MessageKind.OpenBlock);
                var headerStorage = new MessageHeader[1];
                headerStorage[0]  = header;
                var headerBytes   = MemoryMarshal.Cast <MessageHeader, byte>(headerStorage);
                headerBytes.CopyTo(data);

                return(MessageHeader.SizeInBytes);
            });

            _socket.ExpectReceive(data =>
            {
                data.Clear();
                Assert.True(data.Length == OpenBlockRequest.SizeInBytes - MessageHeader.SizeInBytes);

                var request = OpenBlockRequest.From(_r1, _c0, _zero);
                request.Span.Slice(16).CopyTo(data);

                return(OpenBlockRequest.SizeInBytes - MessageHeader.SizeInBytes);
            });

            _socket.ExpectConnected(() => true);
            _socket.ExpectConnected(() => true);

            _socket.ExpectSend(data =>
            {
                Assert.Equal(OpenBlockResponse.SizeInBytes, data.Length);
                var response = new OpenBlockResponse(data);
                Assert.Equal(OpenBlockResponse.SizeInBytes, BinaryPrimitives.ReadInt32LittleEndian(data));
                Assert.Equal(_r1, response.MessageHeader.RequestId); // request ID
                Assert.Equal(_c0, response.MessageHeader.ClientId);  // client ID field empty
                result = response.UncommittedBlockId;
                return(OpenBlockResponse.SizeInBytes);
            });

            Assert.True(_clientConn.HandleRequest());

            Assert.True(_dispatcher.HandleRequest());

            Assert.True(_chainController.HandleRequest());

            Assert.True(_dispatcher.HandleRequest());

            Assert.True(_clientConn.HandleResponse());

            _socket.ExpectAllDone();

            return(result.Value);
        }
Exemple #4
0
        public void OpenGetBlockHandle()
        {
            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);

                // Get block handle
                var clientId           = new ClientId();
                var blockHandleRequest = GetBlockHandleRequest.From(
                    new RequestId(1), clientId, openBlockResponse.UncommittedBlockId);
                socket.Send(blockHandleRequest.Span);

                var blockHandleResponse = new GetBlockHandleResponse(new byte[GetBlockHandleResponse.SizeInBytes]);
                socket.Receive(blockHandleResponse.Span);

                Assert.Equal(GetBlockHandleStatus.Success, blockHandleResponse.Status);
                Assert.Equal(openBlockResponse.Handle, blockHandleResponse.Handle);
                Assert.Equal(default(ClientId), blockHandleResponse.MessageHeader.ClientId);
                Assert.Equal(new RequestId(1), blockHandleResponse.MessageHeader.RequestId);
            }
            finally
            {
                socket.Close();
                instance.Stop();
            }
        }
Exemple #5
0
        private static BlockHandle OpenBlock(CommittedBlockId parentId, ISocketLike socket, ILog log)
        {
            var openBlockRequest = OpenBlockRequest.From(
                RequestId.MinRequestId, ClientId.MinClientId, parentId);

            socket.Send(openBlockRequest.Span);

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

            socket.Receive(openBlockResponse.Span);

            if (openBlockResponse.Status != OpenBlockStatus.Success)
            {
                throw new InvalidOperationException("Failed to open block.");
            }

            log.Log(LogSeverity.Info, "Block opened, writing coins...");

            return(openBlockResponse.Handle);
        }
Exemple #6
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);
            }
        }
Exemple #7
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();
            }
        }
Exemple #8
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();
            }
        }