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); }
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); }
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); }
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(); } }
public OpenBlockResponse OpenBlock(OpenBlockRequest request) { // The request associated to the genesis block does not come with a valid parent. var status = _store.TryOpenBlock(request.ParentId, out var block); switch (status) { case OpenBlockStatus.Success: RefreshAndPropagateLineage(); return(new OpenBlockResponse(ref request.MessageHeader, request.Mask, block.Alias, block.BlockId, _pool)); case OpenBlockStatus.ParentNotFound: return(new OpenBlockResponse(ref request.MessageHeader, Messaging.OpenBlockStatus.ParentNotFound, _pool)); default: throw new NotSupportedException(); } }
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); }
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); } }
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(); } }
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(); } }