示例#1
0
        /// <inheritdoc/>
        public async Task <FeeProposalPayload> MultiSigMemberProposedInteropFeeAsync(string requestId, ulong feeAmount, PubKey pubKey)
        {
            using (await this.asyncLockObject.LockAsync().ConfigureAwait(false))
            {
                // If this node does not have the fee proposal, return and wait for the matured blocks sync manager to find and create it.
                InteropConversionRequestFee interopConversionRequestFee = GetInteropConversionRequestFeeLocked(requestId);
                if (interopConversionRequestFee == null)
                {
                    return(null);
                }

                // Check if the incoming proposal has not yet concluded and that the node has not yet proposed it.
                if (!HasFeeProposalBeenConcluded(interopConversionRequestFee) && !interopConversionRequestFee.FeeProposals.Any(p => p.PubKey == pubKey.ToHex()))
                {
                    // Check that the fee proposal is in range.
                    if (!IsFeeWithinAcceptableRange(interopConversionRequestFee.FeeProposals, requestId, feeAmount, pubKey))
                    {
                        return(null);
                    }

                    interopConversionRequestFee.FeeProposals.Add(new InterOpFeeToMultisig()
                    {
                        BlockHeight = interopConversionRequestFee.BlockHeight, PubKey = pubKey.ToHex(), FeeAmount = feeAmount
                    });
                    this.interopRequestKeyValueStore.SaveValueJson(interopConversionRequestFee.RequestId, interopConversionRequestFee, true);

                    this.logger.LogDebug($"Received conversion request proposal '{requestId}' from '{pubKey}', proposing fee of {new Money(feeAmount)}.");
                }

                // This node would have proposed this fee if the InteropConversionRequestFee object exists.
                InterOpFeeToMultisig myProposal = interopConversionRequestFee.FeeProposals.First(p => p.PubKey == this.federationManager.CurrentFederationKey.PubKey.ToHex());
                string signature = this.federationManager.CurrentFederationKey.SignMessage(interopConversionRequestFee.RequestId + myProposal.FeeAmount);
                return(FeeProposalPayload.Reply(interopConversionRequestFee.RequestId, myProposal.FeeAmount, interopConversionRequestFee.BlockHeight, signature));
            }
        }
        private async Task ProcessFeeProposalAsync(FeeProposalPayload payload)
        {
            if (!this.federationManager.IsFederationMember)
            {
                return;
            }

            // Check that the payload is signed by a multisig federation member.
            PubKey pubKey;

            try
            {
                pubKey = PubKey.RecoverFromMessage(payload.RequestId + payload.FeeAmount, payload.Signature);

                if (!this.federationManager.IsMultisigMember(pubKey))
                {
                    this.logger.LogWarning("Received unverified fee proposal payload for '{0}' from pubkey '{1}'.", payload.RequestId, pubKey?.ToHex());
                    return;
                }
            }
            catch (Exception)
            {
                this.logger.LogWarning("Received malformed fee proposal payload for '{0}'.", payload.RequestId);
                return;
            }

            // Reply back to the peer with this node's proposal.
            FeeProposalPayload replyToPayload = await this.conversionRequestFeeService.MultiSigMemberProposedInteropFeeAsync(payload.RequestId, payload.FeeAmount, pubKey).ConfigureAwait(false);

            if (payload.IsRequesting && replyToPayload != null)
            {
                await this.AttachedPeer.SendMessageAsync(replyToPayload).ConfigureAwait(false);
            }
        }
示例#3
0
        /// <summary>
        /// Submits this node's fee proposal. This methods must be called from within <see cref="asyncLockObject"/>.
        /// </summary>
        /// <param name="interopConversionRequestFee">The request we are currently processing.</param>
        /// <returns>The awaited task.</returns>
        private async Task SubmitProposalForInteropFeeForConversionRequestLockedAsync(InteropConversionRequestFee interopConversionRequestFee)
        {
            // Check if this node has already proposed its fee.
            if (!interopConversionRequestFee.FeeProposals.Any(p => p.PubKey == this.federationManager.CurrentFederationKey.PubKey.ToHex()))
            {
                if (!EstimateConversionTransactionFee(out ulong candidateFee))
                {
                    return;
                }

                interopConversionRequestFee.FeeProposals.Add(new InterOpFeeToMultisig()
                {
                    BlockHeight = interopConversionRequestFee.BlockHeight, PubKey = this.federationManager.CurrentFederationKey.PubKey.ToHex(), FeeAmount = candidateFee
                });
                this.interopRequestKeyValueStore.SaveValueJson(interopConversionRequestFee.RequestId, interopConversionRequestFee, true);

                this.logger.LogDebug($"Adding this node's proposal fee of {candidateFee} for conversion request id '{interopConversionRequestFee.RequestId}'.");
            }

            this.logger.LogDebug($"{interopConversionRequestFee.FeeProposals.Count} node(s) has proposed a fee for conversion request id '{interopConversionRequestFee.RequestId}'.");

            if (HasFeeProposalBeenConcluded(interopConversionRequestFee))
            {
                // Only update the proposal state if it is ProposalInProgress and save it.
                if (interopConversionRequestFee.State == InteropFeeState.ProposalInProgress)
                {
                    interopConversionRequestFee.State = InteropFeeState.AgreeanceInProgress;
                    this.interopRequestKeyValueStore.SaveValueJson(interopConversionRequestFee.RequestId, interopConversionRequestFee, true);

                    IEnumerable <long> values = interopConversionRequestFee.FeeProposals.Select(s => Convert.ToInt64(s.FeeAmount));
                    this.logger.LogDebug($"Proposal fee for request id '{interopConversionRequestFee.RequestId}' has concluded, average amount: {values.Average()}");
                }
            }

            InterOpFeeToMultisig myProposal = interopConversionRequestFee.FeeProposals.First(p => p.PubKey == this.federationManager.CurrentFederationKey.PubKey.ToHex());
            string signature = this.federationManager.CurrentFederationKey.SignMessage(interopConversionRequestFee.RequestId + myProposal.FeeAmount);

            await this.federatedPegBroadcaster.BroadcastAsync(FeeProposalPayload.Request(interopConversionRequestFee.RequestId, myProposal.FeeAmount, interopConversionRequestFee.BlockHeight, signature)).ConfigureAwait(false);
        }