public static Effect ToEffect(this AtomicEffectModel effectModel, AccountWrapper accountWrapper) { var effect = XdrConverter.Deserialize <Effect>(effectModel.RawEffect); effect.AccountWrapper = accountWrapper; return(effect); }
public void XdrPrimitiveTypesSerialization(PrimitiveTypes original) { var serialized = XdrConverter.Serialize(original); var rehydrated = XdrConverter.Deserialize <PrimitiveTypes>(serialized); rehydrated.Should().BeEquivalentTo(original, opt => opt.Excluding(d => d.NotSearialized), "deserialized object should match original"); }
public static QuantumModel FromQuantumContainer(MessageEnvelope quantum, List <Effect> effects, int[] accounts, byte[] buffer) { if (quantum == null) { throw new ArgumentNullException(nameof(quantum)); } if (accounts == null) { throw new ArgumentNullException(nameof(accounts)); } if (effects == null) { throw new ArgumentNullException(nameof(effects)); } var quantumMessage = (Quantum)quantum.Message; using var writer = new XdrBufferWriter(buffer); XdrConverter.Serialize(new QuantumContainer { Quantum = quantum, Effects = effects }, writer); return(new QuantumModel { Apex = quantumMessage.Apex, Accounts = accounts, Bin = writer.ToArray() }); }
public static MessageEnvelope ToMessageEnvelope(this QuantumModel quantum) { if (quantum == null) { throw new ArgumentNullException(nameof(quantum)); } return(XdrConverter.Deserialize <MessageEnvelope>(quantum.RawQuantum)); }
public static AtomicEffectModel FromEffect(this Effect effect, int index) { return(new AtomicEffectModel { ApexIndex = index, RawEffect = XdrConverter.Serialize(effect) }); }
public static void Init() { var allTypes = typeof(TestDynamicSerializersInitializer).Assembly.GetTypes(); foreach (var type in allTypes) { XdrConverter.RegisterSerializer(type); } }
public void AssetsNullValueSerializationTest() { var asset = new AssetSettings { Code = "XLM" }; var rawData = XdrConverter.Serialize(asset); asset = XdrConverter.Deserialize <AssetSettings>(rawData); Assert.AreEqual(null, asset.Issuer); }
public static IncomingMessage ToIncomingMessage(this MessageEnvelope envelope, XdrBufferWriter writer) { if (envelope == null) { throw new ArgumentNullException(nameof(envelope)); } XdrConverter.Serialize(envelope.Message, writer); var messageHash = writer.ToArray().ComputeHash(); return(new IncomingMessage(envelope, messageHash)); }
public static byte[] ToByteArray(this object objToSerialize, XdrBufferWriter writer) { var bytes = objToSerialize as byte[]; if (bytes != null) { return(bytes); } XdrConverter.Serialize(objToSerialize, writer); return(writer.ToArray()); }
/// <summary> /// Submit message to the constellation. /// </summary> /// <param name="envelope"></param> /// <returns></returns> public async Task <QuantumResult> SendMessage(MessageEnvelope envelope) { if (!envelope.IsSignedBy(Config.ClientKeyPair)) { envelope.Sign(Config.ClientKeyPair); } QuantumResult result = null; if (envelope.Message.MessageId != default) { result = new QuantumResult(envelope, ConstellationInfo); result.ScheduleExpiration(RequestTimeout); collator.Add(result); } using (var writerBuffer = Rent(1024)) { try { var writer = new XdrBufferWriter(writerBuffer.Buffer); XdrConverter.Serialize(envelope, writer); await sendMessageSemaphore.WaitAsync(); await webSocket.SendAsync(writerBuffer.Buffer.AsMemory(0, writer.Length), WebSocketMessageType.Binary, true, cancellationTokenSource.Token); } catch (WebSocketException e) { if (result != null) { result.SetException(e); } await CloseConnection(WebSocketCloseStatus.ProtocolError, e.Message); } catch (Exception e) { if (result == null) { throw; } result.SetException(e); } finally { sendMessageSemaphore.Release(); } } return(result); }
public static byte[] ComputeHash(this object objToSerialize) { var bytes = objToSerialize as byte[]; if (bytes != null) { return(SHA256.Create().ComputeHash(bytes)); } using var buffer = XdrBufferFactory.Rent(); using var writer = new XdrBufferWriter(buffer.Buffer); XdrConverter.Serialize(objToSerialize, writer); var hash = SHA256.Create().ComputeHash(buffer.Buffer, 0, writer.Length); return(hash); }
public void XdrInheritanceSerialization() { var mammal = GenerateMammal(); var serializedMammal = XdrConverter.Serialize(mammal); XdrConverter.Deserialize <Vertebrate>(serializedMammal).Should().BeEquivalentTo(mammal); XdrConverter.Deserialize <Tetrapod>(serializedMammal).Should().BeEquivalentTo(mammal); XdrConverter.Deserialize <Mammal>(serializedMammal).Should().BeEquivalentTo(mammal); var fish = GenerateFish(); var serializedFish = XdrConverter.Serialize(fish); XdrConverter.Deserialize <Vertebrate>(serializedFish).Should().BeEquivalentTo(fish); XdrConverter.Deserialize <Fish>(serializedFish).Should().BeEquivalentTo(fish); }
public void XdrPrimitiveTypesSerializationPerformance() { var iterations = 1_000_000; var original = GeneratePrimitives().Skip(1).First(); PerfCounter.MeasureTime(() => { for (var i = 0; i < iterations; i++) { var serialized = XdrConverter.Serialize(original); var rehydrated = XdrConverter.Deserialize <PrimitiveTypes>(serialized); } }, () => { return($"{typeof(PrimitiveTypes).Name} serialization - {iterations} iterations."); }); }
public void XdrInheritanceSerializationPerformance() { var iterations = 1_000_000; var original = GeneratePrimitives().First(); var mammal = GenerateMammal(); PerfCounter.MeasureTime(() => { for (var i = 0; i < iterations; i++) { var serializedMammal = XdrConverter.Serialize(mammal); XdrConverter.Deserialize <Vertebrate>(serializedMammal); } }, () => { return($"Inheritance serialization - {iterations} iterations."); }); }
public virtual async Task SendMessage(MessageEnvelope envelope) { await sendMessageSemaphore.WaitAsync(); try { Global.ExtensionsManager.BeforeSendMessage(this, envelope); if (!envelope.IsSignedBy(Global.Settings.KeyPair.PublicKey)) { envelope.Sign(Global.Settings.KeyPair); } using var buffer = XdrBufferFactory.Rent(); using var writer = new XdrBufferWriter(buffer.Buffer); XdrConverter.Serialize(envelope, writer); if (webSocket == null) { throw new ObjectDisposedException(nameof(webSocket)); } if (webSocket.State == WebSocketState.Open) { await webSocket.SendAsync(buffer.AsSegment(0, writer.Length), WebSocketMessageType.Binary, true, cancellationToken); } Global.ExtensionsManager.AfterSendMessage(this, envelope); } catch (Exception exc) { if (exc is OperationCanceledException || exc is WebSocketException socketException && (socketException.WebSocketErrorCode == WebSocketError.InvalidState)) { return; } Global.ExtensionsManager.SendMessageFailed(this, envelope, exc); throw; } finally { sendMessageSemaphore.Release(); } }
/// <summary> /// Signs an envelope with a given <see cref="KeyPair"/> and appends the signature to the <see cref="MessageEnvelope.Signatures"/>. /// </summary> /// <param name="messageEnvelope">Envelope to sign</param> /// <param name="keyPair">Key pair to use for signing</param> /// <param name="buffer">Buffer to use for computing hash code.</param> public static MessageEnvelope Sign(this MessageEnvelope messageEnvelope, KeyPair keyPair, byte[] buffer) { if (messageEnvelope == null) { throw new ArgumentNullException(nameof(messageEnvelope)); } if (keyPair == null) { throw new ArgumentNullException(nameof(keyPair)); } if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } using var writer = new XdrBufferWriter(buffer); XdrConverter.Serialize(messageEnvelope.Message, writer); var signature = writer.ToArray().ComputeHash().Sign(keyPair); messageEnvelope.Signatures.Add(signature); return(messageEnvelope); }
private async Task <List <WithdrawalWrapper> > GetWithdrawals(AccountStorage accountStorage, ConstellationSettings constellationSettings) { var withdrawalApexes = accountStorage.GetAll().Where(a => a.Account.Withdrawal != default).Select(a => a.Account.Withdrawal).ToArray(); if (withdrawalApexes.Length < 1) { return(new List <WithdrawalWrapper>()); } var withdrawalQuanta = await storage.LoadQuanta(withdrawalApexes); var withdrawals = withdrawalQuanta .Select(w => { var withdrawalQuantum = XdrConverter.Deserialize <MessageEnvelope>(w.Bin); var withdrawalRequest = ((WithdrawalRequest)((RequestQuantum)withdrawalQuantum.Message).RequestMessage); withdrawalQuantum.TryAssignAccountWrapper(accountStorage); return(WithdrawalWrapperExtensions.GetWithdrawal(withdrawalQuantum, constellationSettings)); }); return(withdrawals.OrderBy(w => w.Apex).ToList()); }
public void OrderSerializationTest() { var pubkey = new byte[32]; var signature = new byte[64]; Array.Fill(pubkey, (byte)10); Array.Fill(signature, (byte)64); var original = new OrderRequest() { Account = 1, Amount = 2131231, RequestId = 1, TimeInForce = TimeInForce.ImmediateOrCancel, Asset = 5, Price = 23423.4325 }; var message = new MessageEnvelope() { Message = original, Signatures = new List <Ed25519Signature> { new Ed25519Signature() { Signer = pubkey, Signature = signature } } }; var deserializedMessage = XdrConverter.Deserialize <MessageEnvelope>(XdrConverter.Serialize(message)); var deserialized = deserializedMessage.Message as OrderRequest; Assert.AreEqual(pubkey, deserializedMessage.Signatures[0].Signer.Data); Assert.AreEqual(signature, deserializedMessage.Signatures[0].Signature); Assert.AreEqual(original.Account, deserialized.Account); Assert.AreEqual(original.Amount, deserialized.Amount); Assert.AreEqual(original.TimeInForce, deserialized.TimeInForce); Assert.AreEqual(original.Asset, deserialized.Asset); Assert.AreEqual(original.Nonce, deserialized.Nonce); Assert.AreEqual(original.Price, deserialized.Price); }
public static QuantumModel FromQuantum(MessageEnvelope quantum) { if (quantum == null) { throw new ArgumentNullException(nameof(quantum)); } var quantumMessage = (Quantum)quantum.Message; var account = 0; if (quantumMessage is RequestQuantum requestQuantum) { account = requestQuantum.RequestMessage.Account; } return(new QuantumModel { Apex = quantumMessage.Apex, Account = account, RawQuantum = XdrConverter.Serialize(quantum), Type = (int)quantumMessage.MessageType, TimeStamp = quantumMessage.Timestamp }); }
public static QuantumContainer ToQuantumContainer(this QuantumModel quantum, AccountStorage accountStorage = null) { if (quantum == null) { throw new ArgumentNullException(nameof(quantum)); } var quantumContainer = XdrConverter.Deserialize <QuantumContainer>(quantum.Bin); if (accountStorage != null) { foreach (var effect in quantumContainer.Effects) { if (effect.Account == 0) { continue; } effect.AccountWrapper = accountStorage.GetAccount(effect.Account); } } return(quantumContainer); }
/// <summary> /// Fetches all quanta where apex is greater than the specified one. /// </summary> /// <param name="apex"></param> /// <param name="count">Count of quanta to load. Loads all if equal or less than 0</param> /// <returns></returns> public async Task <List <MessageEnvelope> > GetQuantaAboveApex(long apex, int count = 0) { var quantaModels = await storage.LoadQuantaAboveApex(apex, count); return(quantaModels.OrderBy(q => q.Apex).Select(q => XdrConverter.Deserialize <MessageEnvelope>(q.Bin)).ToList()); }
private async Task Listen() { try { while (webSocket.State != WebSocketState.Closed && webSocket.State != WebSocketState.Aborted && !cancellationTokenSource.Token.IsCancellationRequested) { var messageType = await webSocket.GetWebsocketBuffer(readerBuffer, cancellationTokenSource.Token); if (cancellationTokenSource.Token.IsCancellationRequested) { break; } //the client send close message if (messageType == WebSocketMessageType.Close) { if (webSocket.State != WebSocketState.CloseReceived) { continue; } await sendMessageSemaphore.WaitAsync(); try { await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } finally { sendMessageSemaphore.Release(); cancellationTokenSource.Cancel(); } continue; } try { var envelope = XdrConverter.Deserialize <MessageEnvelope>(new XdrBufferReader(readerBuffer.Buffer)); OnMessage.Invoke(envelope); } catch { OnException?.Invoke(new UnexpectedMessageException("Failed to deserialize a response message received from the server.")); } } } catch (OperationCanceledException) { } catch (Exception e) { var status = WebSocketCloseStatus.InternalServerError; //connection has been already closed by the other side if ((e as WebSocketException)?.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) { return; } string errorDescription = null; if (e is ConnectionCloseException closeException) { status = closeException.Status; errorDescription = closeException.Description; } else if (e is FormatException) { status = WebSocketCloseStatus.ProtocolError; } else { logger.Error(e); } await CloseConnection(status, errorDescription); } finally { _ = Task.Factory.StartNew(() => OnClose?.Invoke()); } }
public async Task AlphaRestartWithQuantaDelayTest(bool invalidHash, bool invalidClientSignature, bool invalidAlphaSignature) { var environment = new IntegrationTestEnvironment(); await environment.PrepareConstellation(1, 3); var lastApex = environment.AlphaWrapper.Context.QuantumStorage.CurrentApex; var lastHash = environment.AlphaWrapper.Context.QuantumStorage.LastQuantumHash; var clientPk = environment.Clients.First(); var client = environment.AlphaWrapper.Context.AccountStorage.GetAccount(clientPk); //wait while all auditors will process all available quanta await environment.AssertConstellationApex(lastApex, TimeSpan.FromSeconds(5)); //generate quantum that will not be processed by Alpha var request = new AccountDataRequest { Account = client.Id, RequestId = DateTime.UtcNow.Ticks, AccountWrapper = client } .CreateEnvelope() .Sign(clientPk); var quantum = new RequestQuantum { Apex = lastApex + 1, PrevHash = lastHash, RequestEnvelope = request, Timestamp = DateTime.UtcNow.Ticks }; var quantumEnvelope = quantum .CreateEnvelope(); var result = await environment.ProcessQuantumIsolated(quantumEnvelope); quantum.EffectsHash = result.effectsHash; quantumEnvelope.Sign(environment.AlphaWrapper.Settings.KeyPair); await environment.AlphaWrapper.Shutdown(); await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Running, TimeSpan.FromSeconds(10)))); //handle quantum await Task.WhenAll(environment.AuditorWrappers.Select(a => { var rawQuantum = quantumEnvelope.ToByteArray(); var auditorsQuantum = XdrConverter.Deserialize <MessageEnvelope>(rawQuantum); return(a.Context.QuantumHandler.HandleAsync(auditorsQuantum)); })); //change quantum environment.AuditorWrappers.ForEach(a => { a.Context.QuantumStorage.GetQuantaBacth(lastApex + 1, 1, out var quanta); var quantum = quanta.First(); if (invalidHash) { ((Quantum)quantum.Message).Timestamp = DateTime.UtcNow.Ticks; } if (invalidClientSignature) { var request = (RequestQuantum)quantum.Message; request.RequestEnvelope.Signatures.Clear(); request.RequestEnvelope.Sign(KeyPair.Random()); } if (invalidAlphaSignature) { quantum.Signatures.Clear(); quantum.Sign(KeyPair.Random()); } }); await environment.AlphaWrapper.Run(); var expectedState = invalidHash || invalidClientSignature || invalidAlphaSignature ? ApplicationState.Failed : ApplicationState.Ready; await IntegrationTestEnvironmentExtensions.AssertState(environment.AlphaWrapper.Startup, expectedState, TimeSpan.FromSeconds(30)); if (expectedState == ApplicationState.Failed) { return; } await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Ready, TimeSpan.FromSeconds(10)))); await environment.AssertConstellationApex(lastApex + 1, TimeSpan.FromSeconds(5)); }
public async Task <MessageEnvelope> GetQuantum(long apex) { var quantumModel = await storage.LoadQuantum(apex); return(XdrConverter.Deserialize <MessageEnvelope>(quantumModel.Bin)); }
public async Task Listen() { try { while (webSocket.State != WebSocketState.Closed && webSocket.State != WebSocketState.Aborted && !cancellationToken.IsCancellationRequested) { var result = await webSocket.GetWebsocketBuffer(MaxMessageSize, cancellationToken); using (result.messageBuffer) if (!cancellationToken.IsCancellationRequested) { //the client send close message if (result.messageType == WebSocketMessageType.Close) { if (webSocket.State != WebSocketState.CloseReceived) { continue; } await sendMessageSemaphore.WaitAsync(); try { var timeoutTokenSource = new CancellationTokenSource(1000); await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Close", CancellationToken.None); } finally { sendMessageSemaphore.Release(); cancellationTokenSource.Cancel(); } } else { MessageEnvelope envelope = null; try { var reader = new XdrBufferReader(result.messageBuffer.Buffer, result.messageBuffer.Length); envelope = XdrConverter.Deserialize <MessageEnvelope>(reader); if (!await HandleMessage(envelope)) { throw new UnexpectedMessageException($"No handler registered for message type {envelope.Message.MessageType}."); } } catch (BaseClientException exc) { Global.ExtensionsManager.HandleMessageFailed(this, envelope, exc); var statusCode = exc.GetStatusCode(); //prevent recursive error sending if (!(envelope == null || envelope.Message is ResultMessage)) { _ = SendMessage(envelope.CreateResult(statusCode)); } if (statusCode == ResultStatusCodes.InternalError || !Global.IsAlpha) { logger.Error(exc); } } } } } } catch (OperationCanceledException) { } catch (Exception e) { Global.ExtensionsManager.HandleMessageFailed(this, null, e); var closureStatus = WebSocketCloseStatus.InternalServerError; var desc = default(string); if (e is WebSocketException webSocketException && webSocketException.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) //connection already closed by the other side { return; }