/// <inheritdoc/> public override void CheckTransaction(MempoolValidationContext context) { if (context.Transaction.IsCoinBase || context.Transaction.IsCoinStake) { return; } // This will raise a consensus error if there is a voting request and it can't be decoded. JoinFederationRequest request = JoinFederationRequestBuilder.Deconstruct(context.Transaction, this.encoder); if (request == null) { return; } if (FederationVotingController.IsMultisigMember(this.network, request.PubKey)) { this.logger.LogTrace("(-)[INVALID_MULTISIG_VOTING]"); context.State.Fail(MempoolErrors.VotingRequestInvalidMultisig, $"{context.Transaction.GetHash()} has an invalid voting request for a multisig member.").Throw(); } // Check collateral amount? if (request.CollateralAmount.ToDecimal(MoneyUnit.BTC) != CollateralPoAMiner.MinerCollateralAmount) { this.logger.LogTrace("(-)[INVALID_COLLATERAL_REQUIREMENT]"); context.State.Fail(MempoolErrors.InvalidCollateralRequirement, $"{context.Transaction.GetHash()} has a voting request with an invalid colateral requirement.").Throw(); } if (!(this.federationManager is CollateralFederationManager federationManager)) { return; } // Prohibit re-use of collateral addresses. Script script = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(request.CollateralMainchainAddress); string collateralAddress = script.GetDestinationAddress(this.network).ToString(); CollateralFederationMember owner = federationManager.CollateralAddressOwner(this.votingManager, VoteKey.AddFederationMember, collateralAddress); if (owner != null && owner.PubKey != request.PubKey) { this.logger.LogTrace("(-)[INVALID_COLLATERAL_REUSE]"); context.State.Fail(MempoolErrors.VotingRequestInvalidCollateralReuse, $"{context.Transaction.GetHash()} has a voting request that's re-using collateral.").Throw(); } }
private IActionResult VoteAddKickFedMember(CollateralFederationMemberModel request, bool addMember) { Guard.NotNull(request, nameof(request)); if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } if (!this.fedManager.IsFederationMember) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Only federation members can vote", string.Empty)); } try { var key = new PubKey(request.PubKeyHex); if (FederationVotingController.IsMultisigMember(this.network, key)) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Multisig members can't be voted on", string.Empty)); } IFederationMember federationMember = new CollateralFederationMember(key, false, new Money(request.CollateralAmountSatoshis), request.CollateralMainchainAddress); byte[] fedMemberBytes = (this.network.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(federationMember); this.votingManager.ScheduleVote(new VotingData() { Key = addMember ? VoteKey.AddFederationMember : VoteKey.KickFederationMember, Data = fedMemberBytes }); return(this.Ok()); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "There was a problem executing a command.", e.ToString())); } }
protected override List <IFederationMember> LoadFederation() { List <CollateralFederationMemberModel> fedMemberModels = this.keyValueRepo.LoadValueJson <List <CollateralFederationMemberModel> >(federationMembersDbKey); if (fedMemberModels == null) { this.logger.LogTrace("(-)[NOT_FOUND]:null"); return(null); } var federation = new List <IFederationMember>(fedMemberModels.Count); foreach (CollateralFederationMemberModel fedMemberModel in fedMemberModels) { PubKey pubKey = new PubKey(fedMemberModel.PubKeyHex); bool isMultisigMember = FederationVotingController.IsMultisigMember(this.network, pubKey); federation.Add(new CollateralFederationMember(pubKey, isMultisigMember, new Money(fedMemberModel.CollateralAmountSatoshis), fedMemberModel.CollateralMainchainAddress)); } return(federation); }