private async Task ProcessFeeAgreeAsync(FeeAgreePayload 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 vote payload for '{0}' from pubkey '{1}'.", payload.RequestId, pubKey?.ToHex()); return; } } catch (Exception) { this.logger.LogWarning("Received malformed fee vote payload for '{0}'.", payload.RequestId); return; } // Reply back to the peer with this node's amount. FeeAgreePayload replyToPayload = await this.conversionRequestFeeService.MultiSigMemberAgreedOnInteropFeeAsync(payload.RequestId, payload.FeeAmount, pubKey).ConfigureAwait(false); if (payload.IsRequesting && replyToPayload != null) { await this.AttachedPeer.SendMessageAsync(replyToPayload).ConfigureAwait(false); } }
public bool VerifySignatureMessage(string message, byte[] signature, string address) { var sig = Encoders.Base64.EncodeData(signature); var recoverAddress = PubKey.RecoverFromMessage(message, sig); return(recoverAddress.GetAddress(ScriptPubKeyType.Legacy, network).ToString() == address); }
private async Task OnMessageReceivedAsync(INetworkPeer peer, IncomingMessage message) { if (!(message.Message.Payload is InteropCoordinationPayload payload)) { return; } if (!this.federationManager.IsFederationMember) { return; } this.logger.Info("{0} received from '{1}':'{2}'. Request {3} proposing transaction ID {4}.", nameof(InteropCoordinationPayload), peer.PeerEndPoint.Address, peer.RemoteSocketEndpoint.Address, payload.RequestId, payload.TransactionId); if (payload.TransactionId == BigInteger.MinusOne) { return; } // Check that the payload is signed by a federation member. PubKey pubKey; try { pubKey = PubKey.RecoverFromMessage(payload.RequestId + payload.TransactionId, payload.Signature); if (!this.federationManager.IsMultisigMember(pubKey)) { this.logger.Warn("Received unverified coordination payload for {0}. Computed pubkey {1}.", payload.RequestId, pubKey?.ToHex()); return; } } catch (Exception) { this.logger.Warn("Received malformed coordination payload for {0}.", payload.RequestId); return; } BigInteger confirmationCount; try { // Check that the transaction ID in the payload actually exists, and is unconfirmed. confirmationCount = await this.clientProvider.GetClientForChain(payload.DestinationChain) .GetConfirmationCountAsync(payload.TransactionId).ConfigureAwait(false); } catch (Exception) { return; } // We presume that the initial submitter of the transaction must have at least confirmed it. Otherwise just ignore this coordination attempt. if (confirmationCount < 1) { this.logger.Info("Multisig wallet transaction {0} has no confirmations.", payload.TransactionId); return; } this.logger.Info("Multisig wallet transaction {0} has {1} confirmations (request ID: {2}).", payload.TransactionId, confirmationCount, payload.RequestId); this.interopTransactionManager.AddVote(payload.RequestId, payload.TransactionId, pubKey); }
public bool VerifyMessage(string message, string signature) { var key = PubKey.RecoverFromMessage(message, signature); return(key.Hash == Hash); }
private async Task ProcessConversionRequestPayloadAsync(INetworkPeer peer, ConversionRequestPayload payload) { if (!this.federationManager.IsFederationMember) { return; } this.logger.LogDebug("Conversion request payload request for id '{0}' received from '{1}':'{2}' proposing transaction ID '{4}'.", payload.RequestId, peer.PeerEndPoint.Address, peer.RemoteSocketEndpoint.Address, payload.RequestId, payload.TransactionId); if (payload.TransactionId == BigInteger.MinusOne) { return; } // Check that the payload is signed by a multisig federation member. PubKey pubKey; try { pubKey = PubKey.RecoverFromMessage(payload.RequestId + payload.TransactionId, payload.Signature); if (!this.federationManager.IsMultisigMember(pubKey)) { this.logger.LogWarning("Conversion request payload for '{0}'. Computed pubkey '{1}'.", payload.RequestId, pubKey?.ToHex()); return; } } catch (Exception) { this.logger.LogWarning("Received malformed conversion request payload for '{0}'.", payload.RequestId); return; } BigInteger confirmationCount; try { // Check that the transaction ID in the payload actually exists, and is unconfirmed. confirmationCount = await this.ethClientProvider.GetClientForChain(payload.DestinationChain).GetMultisigConfirmationCountAsync(payload.TransactionId).ConfigureAwait(false); } catch (Exception) { return; } // We presume that the initial submitter of the transaction must have at least confirmed it. Otherwise just ignore this coordination attempt. if (confirmationCount < 1) { this.logger.LogInformation("Multisig wallet transaction {0} has no confirmations.", payload.TransactionId); return; } // Only add votes if the conversion request has not already been finalized. ConversionRequest conversionRequest = this.conversionRequestRepository.Get(payload.RequestId); if (conversionRequest != null && conversionRequest.RequestStatus != ConversionRequestStatus.VoteFinalised) { this.conversionRequestCoordinationService.AddVote(payload.RequestId, payload.TransactionId, pubKey); } if (payload.IsRequesting) { string signature = this.federationManager.CurrentFederationKey.SignMessage(payload.RequestId + payload.TransactionId); await this.AttachedPeer.SendMessageAsync(ConversionRequestPayload.Reply(payload.RequestId, payload.TransactionId, signature, payload.DestinationChain)).ConfigureAwait(false); } }
private void OnBlockConnected(BlockConnected blockConnectedData) { if (!(this.network.Consensus.ConsensusFactory is CollateralPoAConsensusFactory consensusFactory)) { return; } List <Transaction> transactions = blockConnectedData.ConnectedBlock.Block.Transactions; var encoder = new JoinFederationRequestEncoder(this.loggerFactory); for (int i = 0; i < transactions.Count; i++) { Transaction tx = transactions[i]; try { JoinFederationRequest request = JoinFederationRequestBuilder.Deconstruct(tx, encoder); if (request == null) { continue; } // Skip if the member already exists. if (this.votingManager.IsFederationMember(request.PubKey)) { continue; } // Check if the collateral amount is valid. decimal collateralAmount = request.CollateralAmount.ToDecimal(MoneyUnit.BTC); var expectedCollateralAmount = CollateralFederationMember.GetCollateralAmountForPubKey((PoANetwork)this.network, request.PubKey); if (collateralAmount != expectedCollateralAmount) { this.logger.LogDebug("Ignoring voting collateral amount '{0}', when expecting '{1}'.", collateralAmount, expectedCollateralAmount); continue; } // Fill in the request.removalEventId (if any). Script collateralScript = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(request.CollateralMainchainAddress); var collateralFederationMember = new CollateralFederationMember(request.PubKey, false, request.CollateralAmount, collateralScript.GetDestinationAddress(this.counterChainNetwork).ToString()); byte[] federationMemberBytes = consensusFactory.SerializeFederationMember(collateralFederationMember); // Nothing to do if already voted. if (this.votingManager.AlreadyVotingFor(VoteKey.AddFederationMember, federationMemberBytes)) { this.logger.LogDebug("Skipping because already voted for adding '{0}'.", request.PubKey.ToHex()); continue; } // Populate the RemovalEventId. Poll poll = this.votingManager.GetFinishedPolls().FirstOrDefault(x => x.IsExecuted && x.VotingData.Key == VoteKey.KickFederationMember && x.VotingData.Data.SequenceEqual(federationMemberBytes)); request.RemovalEventId = (poll == null) ? Guid.Empty : new Guid(poll.PollExecutedBlockData.Hash.ToBytes().TakeLast(16).ToArray()); // Check the signature. PubKey key = PubKey.RecoverFromMessage(request.SignatureMessage, request.Signature); if (key.Hash != request.CollateralMainchainAddress) { this.logger.LogDebug("Invalid collateral address validation signature for joining federation via transaction '{0}'", tx.GetHash()); continue; } // Vote to add the member. this.logger.LogDebug("Voting to add federation member '{0}'.", request.PubKey.ToHex()); this.votingManager.ScheduleVote(new VotingData() { Key = VoteKey.AddFederationMember, Data = federationMemberBytes }); } catch (Exception err) { this.logger.LogDebug(err.Message); } } }
public void OnBlockConnected(BlockConnected blockConnectedData) { if (!(this.network.Consensus.ConsensusFactory is CollateralPoAConsensusFactory consensusFactory)) { return; } // Only mining federation members vote to include new members. if (this.federationManager.CurrentFederationKey?.PubKey == null) { return; } List <IFederationMember> modifiedFederation = null; List <Transaction> transactions = blockConnectedData.ConnectedBlock.Block.Transactions; var encoder = new JoinFederationRequestEncoder(); for (int i = 0; i < transactions.Count; i++) { Transaction tx = transactions[i]; try { JoinFederationRequest request = JoinFederationRequestBuilder.Deconstruct(tx, encoder); if (request == null) { continue; } // Skip if the member already exists. if (this.votingManager.IsFederationMember(request.PubKey)) { continue; } // Only mining federation members vote to include new members. modifiedFederation ??= this.votingManager.GetModifiedFederation(blockConnectedData.ConnectedBlock.ChainedHeader); if (!modifiedFederation.Any(m => m.PubKey == this.federationManager.CurrentFederationKey.PubKey)) { this.logger.LogDebug($"Ignoring as member '{this.federationManager.CurrentFederationKey.PubKey}' is not part of the federation at block '{blockConnectedData.ConnectedBlock.ChainedHeader}'."); return; } // Check if the collateral amount is valid. decimal collateralAmount = request.CollateralAmount.ToDecimal(MoneyUnit.BTC); var expectedCollateralAmount = CollateralFederationMember.GetCollateralAmountForPubKey((PoANetwork)this.network, request.PubKey); if (collateralAmount != expectedCollateralAmount) { this.logger.LogDebug("Ignoring voting collateral amount '{0}', when expecting '{1}'.", collateralAmount, expectedCollateralAmount); continue; } // Fill in the request.removalEventId (if any). byte[] federationMemberBytes = JoinFederationRequestService.GetFederationMemberBytes(request, this.network, this.counterChainNetwork); // Nothing to do if already voted. if (this.votingManager.AlreadyVotingFor(VoteKey.AddFederationMember, federationMemberBytes)) { this.logger.LogDebug("Skipping because already voted for adding '{0}'.", request.PubKey.ToHex()); continue; } // Populate the RemovalEventId. JoinFederationRequestService.SetLastRemovalEventId(request, federationMemberBytes, this.votingManager); // Check the signature. PubKey key = PubKey.RecoverFromMessage(request.SignatureMessage, request.Signature); if (key.Hash != request.CollateralMainchainAddress) { this.logger.LogDebug("Invalid collateral address validation signature for joining federation via transaction '{0}'", tx.GetHash()); continue; } // Vote to add the member. this.logger.LogDebug("Voting to add federation member '{0}'.", request.PubKey.ToHex()); this.votingManager.ScheduleVote(new VotingData() { Key = VoteKey.AddFederationMember, Data = federationMemberBytes }); } catch (Exception err) { this.logger.LogError(err.Message); } } }