public AccountWrapper CreateAccount(int id, RawPubKey pubkey, RequestRateLimits rateLimits) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } if (accountIds.ContainsKey(pubkey)) { throw new InvalidOperationException($"Account with public key {pubkey} already exists"); } var acc = new AccountWrapper(new Account { Id = id, Pubkey = pubkey, Balances = new List <Balance>() }, rateLimits ); accountIds.Add(pubkey, id); accounts.Add(id, acc); return(acc); }
private bool AddQuanta(RawPubKey pubKey, AuditorState currentState, AuditorState newAuditorState) { if (!currentState.HasMorePendingQuanta || newAuditorState.HasMorePendingQuanta && newAuditorState.PendingQuanta.Count < 1) //prevent spamming { logger.Trace($"Unable to add auditor's {((KeyPair)pubKey).AccountId} quanta."); currentState.HasMorePendingQuanta = false; return(false); } currentState.HasMorePendingQuanta = newAuditorState.HasMorePendingQuanta; var lastAddedApex = currentState.PendingQuanta.LastOrDefault()?.Message.MessageId ?? -1; var alphaPubkey = (RawPubKey)Context.Settings.KeyPair.PublicKey; foreach (var envelope in newAuditorState.PendingQuanta) { var currentQuantum = (Quantum)envelope.Message; if (lastAddedApex != -1 && currentQuantum.Apex != lastAddedApex + 1) { return(false); } lastAddedApex = currentQuantum.Apex; if (envelope.Signatures.All(s => !s.Signer.Equals(alphaPubkey)) || !envelope.AreSignaturesValid()) { return(false); } currentState.PendingQuanta.Add(envelope); } logger.Trace($"Auditor's {((KeyPair)pubKey).AccountId} quanta added."); return(true); }
/// <summary> /// Sends the message to the account /// </summary> /// <param name="account">Target account</param> /// <param name="envelope">Message to send</param> public static void Notify(RawPubKey account, MessageEnvelope envelope) { Global.ExtensionsManager.BeforeNotify(account, envelope); if (ConnectionManager.TryGetConnection(account, out Centaurus.AlphaWebSocketConnection connection)) { _ = connection.SendMessage(envelope); } }
public void Add(AuditorResultMessage resultMessage, RawPubKey auditor) { if (!pendingAggregates.TryGetValue(resultMessage.Apex, out var aggregate)) { return; } //add the signature to the aggregate aggregate.Add(resultMessage, auditor); }
public void AuditorConnectionClosed(RawPubKey rawPubKey) { lock (this) { ConnectedAuditors.Remove(rawPubKey); if (!HasMajority && State == ApplicationState.Ready) { State = ApplicationState.Running; } } }
public void RegisterAuditorState(RawPubKey rawPubKey, ConnectionState connectionState) { lock (this) { ConnectedAuditors[rawPubKey] = connectionState; if (HasMajority && State == ApplicationState.Running) { State = ApplicationState.Ready; } } }
public void AuditorConnected(RawPubKey rawPubKey) { lock (this) { ConnectedAuditors.Add(rawPubKey); if (HasMajority && State == ApplicationState.Running) { State = ApplicationState.Ready; } } }
/// <summary> /// Checks that envelope is signed with specified key /// !!!This method doesn't validate signature /// </summary> /// <param name="envelope">Target envelope</param> /// <param name="pubKey">Required signer public key</param> /// <returns>True if signed, otherwise false</returns> public static bool IsSignedBy(this MessageEnvelope envelope, RawPubKey pubKey) { if (envelope == null) { throw new ArgumentNullException(nameof(envelope)); } if (pubKey == null) { throw new ArgumentNullException(nameof(pubKey)); } return(envelope.Signatures.Any(s => s.Signer.Equals(pubKey))); }
/// <summary> /// Sends the message to the account /// </summary> /// <param name="account">Target account</param> /// <param name="envelope">Message to send</param> public static void Notify(this AlphaContext context, RawPubKey account, MessageEnvelope envelope) { if (context == null) { throw new ArgumentNullException(nameof(context)); } context.ExtensionsManager.BeforeNotify(account, envelope); if (context.ConnectionManager.TryGetConnection(account, out AlphaWebSocketConnection connection)) { Task.Factory.StartNew(async() => await connection.SendMessage(envelope)).Unwrap(); } }
public void RemoveState(RawPubKey pubKey) { semaphoreSlim.Wait(); try { allAuditorStates.Remove(pubKey); validAuditorStates.Remove(pubKey); } finally { semaphoreSlim.Release(); } }
/// <summary> /// Retrieve account record by its public key. /// </summary> /// <param name="pubkey">Account public key</param> /// <returns>Account record, or null if not found</returns> public AccountWrapper GetAccount(RawPubKey pubkey) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } var accId = accountIds.GetValueOrDefault(pubkey); if (accId == default) { return(null); } return(GetAccount(accId)); }
public void RemoveAccount(RawPubKey pubkey) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } if (!accountIds.TryGetValue(pubkey, out var id)) { throw new InvalidOperationException($"Account with public key {pubkey} doesn't exist"); } if (!accounts.Remove(id)) { throw new InvalidOperationException($"Account with id {id} doesn't exist"); } if (!accountIds.Remove(pubkey)) { throw new Exception($"Account with public key {pubkey} doesn't exist"); } }
public void Add(AuditorResultMessage result, RawPubKey auditor) { lock (syncRoot) { if (IsProcessed || processedAuditors.Any(a => a.Equals(auditor))) { return; } processedAuditors.Add(auditor); var signature = new Ed25519Signature { Signature = result.Signature, Signer = auditor }; if (signature.IsValid(resultMessageItem.Hash) && !(resultMessageItem.IsTxResultMessage && result.TxSignature == null)) { resultMessageItem.ResultEnvelope.Signatures.Add(signature); if (resultMessageItem.IsTxResultMessage) { var txSignature = new Ed25519Signature { Signature = result.TxSignature, Signer = auditor }; ((ITransactionResultMessage)resultMessageItem.ResultMessage).TxSignatures.Add(txSignature); } } var majorityResult = CheckMajority(); if (majorityResult == MajorityResults.Unknown) { return; } OnResult(majorityResult); resultManager.Remove(resultMessageItem.Apex); IsProcessed = true; } }
public CentaurusResponse(RawPubKey alphaPubKey, RawPubKey[] auditors, int requestTimeout) { AlphaPubkey = alphaPubKey; Auditors = auditors; _ = StartRequestTimer(requestTimeout); }
public static async Task AddAuditorState(RawPubKey pubKey, AuditorState auditorState) { await semaphoreSlim.WaitAsync(); try { if (Global.AppState.State != ApplicationState.Rising) { throw new InvalidOperationException("Auditor state messages can be only handled when Alpha is in rising state"); } if (allAuditorStates.TryGetValue(pubKey, out var pendingAuditorState)) { if (!pendingAuditorState.HasMorePendingQuanta) //check if auditor send all quanta already { return; } allAuditorStates[pubKey].PendingQuanta.AddRange(auditorState.PendingQuanta); allAuditorStates[pubKey].HasMorePendingQuanta = auditorState.HasMorePendingQuanta; } else { allAuditorStates.Add(pubKey, auditorState); } var currentAuditorState = allAuditorStates[pubKey]; if (currentAuditorState.HasMorePendingQuanta) //wait while auditor will send all quanta it has { return; } if (IsStateValid(currentAuditorState)) { validAuditorStates.Add(pubKey, currentAuditorState); } int majority = MajorityHelper.GetMajorityCount(), totalAuditorsCount = MajorityHelper.GetTotalAuditorsCount(); var completedStatesCount = allAuditorStates.Count(s => !s.Value.HasMorePendingQuanta); if (completedStatesCount < majority) { return; } var possibleConsensusCount = (totalAuditorsCount - completedStatesCount) + validAuditorStates.Count; if (validAuditorStates.Count >= majority) { await ApplyAuditorsData(); } else if (possibleConsensusCount < majority) { logger.Error("Majority of auditors are connected, but there is no consensus"); Global.AppState.State = ApplicationState.Failed; } } catch (Exception exc) { logger.Error(exc, "Error on adding auditors state"); Global.AppState.State = ApplicationState.Failed; } finally { semaphoreSlim.Release(); } }
public static void AddAccountCreate(this EffectProcessorsContainer effectProcessors, AccountStorage accountStorage, int accountId, RawPubKey publicKey) { effectProcessors.Add(new AccountCreateEffectProcessor( new AccountCreateEffect { Account = accountId, Pubkey = publicKey, Apex = effectProcessors.Apex }, accountStorage, effectProcessors.Context.Constellation.RequestRateLimits )); }
public void BeforeNotify(RawPubKey pubKey, MessageEnvelope envelope) { OnBeforeNotify?.Invoke(pubKey, envelope); }
public async Task AddAuditorState(RawPubKey pubKey, AuditorState auditorState) { await semaphoreSlim.WaitAsync(); try { if (!applyDataTimer.Enabled) //start timer { applyDataTimer.Start(); } logger.Trace($"Auditor state from {((KeyPair)pubKey).AccountId} received by AlphaCatchup."); if (Context.AppState.State != ApplicationState.Rising) { logger.Warn($"Auditor state messages can be only handled when Alpha is in rising state. State sent by {((KeyPair)pubKey).AccountId}"); return; } if (!allAuditorStates.TryGetValue(pubKey, out var pendingAuditorState)) { pendingAuditorState = new AuditorState { HasMorePendingQuanta = true, PendingQuanta = new List <MessageEnvelope>() }; allAuditorStates.Add(pubKey, pendingAuditorState); logger.Trace($"Auditor state from {((KeyPair)pubKey).AccountId} added."); } if (AddQuanta(pubKey, pendingAuditorState, auditorState)) //check if auditor sent all quanta already { if (pendingAuditorState.HasMorePendingQuanta) //wait while auditor will send all quanta it has { logger.Trace($"Auditor {((KeyPair)pubKey).AccountId} has more quanta. Timer reseted."); applyDataTimer.Reset(); //if timer is running reset it. We need to try to wait all possible auditors data return; } logger.Trace($"Auditor {((KeyPair)pubKey).AccountId} state is validated."); validAuditorStates.Add(pubKey, pendingAuditorState); } int majority = Context.GetMajorityCount(), totalAuditorsCount = Context.GetTotalAuditorsCount(); var completedStatesCount = allAuditorStates.Count(s => !s.Value.HasMorePendingQuanta); if (completedStatesCount == totalAuditorsCount) { await TryApplyAuditorsData(); } } catch (Exception exc) { logger.Error(exc, "Error on adding auditors state"); Context.AppState.State = ApplicationState.Failed; } finally { semaphoreSlim.Release(); } }
public static void AddAccountCreate(this EffectProcessorsContainer effectProcessors, AccountStorage accountStorage, int accountId, RawPubKey publicKey) { effectProcessors.Add(new AccountCreateEffectProcessor( new AccountCreateEffect { AccountId = accountId, Pubkey = publicKey, Apex = effectProcessors.Apex }, accountStorage )); }
public CentaurusQuantumResponse(RawPubKey alphaPubKey, RawPubKey[] auditors, int requestTimeout) : base(alphaPubKey, auditors, requestTimeout) { }
/// <summary> /// Gets the connection by the account public key /// </summary> /// <param name="pubKey">Account public key</param> /// <param name="connection">Current account connection</param> /// <returns>True if connection is found, otherwise false</returns> public static bool TryGetConnection(RawPubKey pubKey, out AlphaWebSocketConnection connection) { return(connections.TryGetValue(pubKey, out connection)); }