private MajorityResults CheckMajority() { int requiredMajority = MajorityHelper.GetMajorityCount(), maxVotes = MajorityHelper.GetTotalAuditorsCount(); //if envelope contains Alpha signature we need to exclude it from count var votesCount = resultMessageItem.ResultEnvelope.Signatures.Count; if (resultMessageItem.ResultEnvelope.IsSignedBy(Global.Settings.KeyPair)) { votesCount--; } //check if we have the majority if (votesCount >= requiredMajority) { return(MajorityResults.Success); } var totalOpposition = processedAuditors.Count - votesCount; var maxPossibleVotes = votesCount + (maxVotes - totalOpposition); if (maxPossibleVotes < requiredMajority) { return(MajorityResults.Unreachable);//no chances to reach the majority } //not enough votes to decided whether the consensus can be reached or not return(MajorityResults.Unknown); }
/// <summary> /// Builds and configures Centaurus vault /// </summary> /// <returns>Transaction cursor</returns> private async Task <long> BuildAndConfigureVault(stellar_dotnet_sdk.responses.AccountResponse vaultAccount) { var majority = MajorityHelper.GetMajorityCount(constellationInitInfo.Auditors.Count()); var sourceAccount = await StellarAccountHelper.GetStellarAccount(vaultAccount.KeyPair); var transactionBuilder = new TransactionBuilder(sourceAccount); transactionBuilder.SetFee(10_000); var existingTrustlines = vaultAccount.Balances .Where(b => b.Asset is stellar_dotnet_sdk.AssetTypeCreditAlphaNum) .Select(b => b.Asset) .Cast <stellar_dotnet_sdk.AssetTypeCreditAlphaNum>(); foreach (var a in constellationInitInfo.Assets) { var asset = a.ToAsset() as stellar_dotnet_sdk.AssetTypeCreditAlphaNum; if (asset == null) //if null than asset is stellar_dotnet_sdk.AssetTypeNative { throw new InvalidOperationException("Native assets are supported by default."); //better to throw exception to avoid confusions with id } if (existingTrustlines.Any(t => t.Code == asset.Code && t.Issuer == asset.Issuer)) { continue; } var trustOperation = new ChangeTrustOperation.Builder(asset, "922337203685.4775807"); transactionBuilder.AddOperation(trustOperation.Build()); } var optionOperationBuilder = new SetOptionsOperation.Builder() .SetMasterKeyWeight(0) .SetLowThreshold(majority) .SetMediumThreshold(majority) .SetHighThreshold(majority); transactionBuilder.AddOperation(optionOperationBuilder.Build()); foreach (var signer in constellationInitInfo.Auditors) { transactionBuilder.AddOperation(new SetOptionsOperation.Builder().SetSigner(Signer.Ed25519PublicKey(signer), 1).Build()); } var transaction = transactionBuilder.Build(); transaction.Sign(Global.Settings.KeyPair); var result = await Global.StellarNetwork.Server.SubmitTransaction(transaction); if (!result.IsSuccess()) { throw new Exception($"Transaction failed. Result Xdr: {result.ResultXdr}"); } var tx = await Global.StellarNetwork.Server.Transactions.Transaction(result.Hash); return(long.Parse(tx.PagingToken)); }
private void CheckSignatures(MessageEnvelope envelope) { if (!MajorityHelper.HasMajority(envelope)) { throw new InvalidOperationException("No majority"); } if (!envelope.AreSignaturesValid()) { throw new InvalidOperationException("Signatures is invalid"); } }
/// <summary> /// Builds and configures Centaurus vault /// </summary> /// <returns>Transaction cursor</returns> private async Task <long> BuildAndConfigureVault(AccountModel vaultAccount) { var majority = MajorityHelper.GetMajorityCount(constellationInitInfo.Auditors.Count()); var sourceAccount = await Context.StellarDataProvider.GetAccountData(vaultAccount.KeyPair.AccountId); var transactionBuilder = new TransactionBuilder(sourceAccount.ToITransactionBuilderAccount()); transactionBuilder.SetFee(10_000); foreach (var a in constellationInitInfo.Assets) { if (a.IsXlm) { throw new InvalidOperationException("Native assets are supported by default."); //better to throw exception to avoid confusions with id } if (vaultAccount.ExistingTrustLines.Any(ta => ta == a.ToString())) { continue; } var trustOperation = new ChangeTrustOperation.Builder(a.ToAsset(), "922337203685.4775807"); transactionBuilder.AddOperation(trustOperation.Build()); } var optionOperationBuilder = new SetOptionsOperation.Builder() .SetMasterKeyWeight(0) .SetLowThreshold(majority) .SetMediumThreshold(majority) .SetHighThreshold(majority); transactionBuilder.AddOperation(optionOperationBuilder.Build()); foreach (var signer in constellationInitInfo.Auditors) { transactionBuilder.AddOperation(new SetOptionsOperation.Builder().SetSigner(Signer.Ed25519PublicKey(signer), 1).Build()); } var transaction = transactionBuilder.Build(); transaction.Sign(Context.Settings.KeyPair); var result = await Context.StellarDataProvider.SubmitTransaction(transaction); if (!result.IsSuccess) { throw new Exception($"Transaction failed. Result Xdr: {result.ResultXdr}"); } var tx = await Context.StellarDataProvider.GetTransaction(result.Hash); return(tx.PagingToken); }
private MajorityResults CheckMajority(out MessageEnvelope consensus) { //TODO: remove the item from storage once the majority succeeded of failed. int requiredMajority = MajorityHelper.GetMajorityCount(), maxVotes = MajorityHelper.GetTotalAuditorsCount(), maxConsensus = 0, totalOpposition = 0; //try to find the majority foreach (var pair in storage) { var votes = pair.Value.Signatures.Count; //check if we have the majority if (votes >= requiredMajority) { //return the messages for the consensus consensus = pair.Value; return(MajorityResults.Success); } //check whether a current message is a potential consensus candidate if (votes > maxConsensus) { //previous consensus candidate won't be able to get the majority - swap it totalOpposition += maxConsensus; maxConsensus = votes; } } //failed to rich consensus consensus = null; var maxPossibleVotes = (maxVotes - totalOpposition) + maxConsensus; if (maxPossibleVotes < requiredMajority) {//no chances to reach the majority return(MajorityResults.Unreachable); } //not enough votes to decided whether the consensus can be reached or not return(MajorityResults.Unknown); }
private static void ValidateSnapshotSignatures(Snapshot snapshot, List <RawPubKey> knownAudiotors) { var majorityCount = MajorityHelper.GetMajorityCount(knownAudiotors.Count); var validSignatures = 0; var signatures = snapshot.Signatures; //set Signatures to null, because snapshot hash computes without it snapshot.Signatures = null; var snapshotHash = snapshot.ComputeHash(); if (signatures != null) { foreach (var signature in signatures) { if (!knownAudiotors.Contains(signature.Signer)) { continue; } if (signature.IsValid(snapshotHash)) { validSignatures++; } if (validSignatures >= majorityCount) { break; } } } if (validSignatures < majorityCount) { throw new Exception("Snapshot has no majority"); } }
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(); } }