private IFederationMember GetFederationMemberForBlockInternal(ChainedHeader chainedHeader, List <IFederationMember> federation) { if (chainedHeader.Height == 0) { return(federation.Last()); } // Try to provide the public key that signed the block. try { var header = chainedHeader.Header as PoABlockHeader; var signature = ECDSASignature.FromDER(header.BlockSignature.Signature); for (int recId = 0; recId < 4; recId++) { PubKey pubKeyForSig = PubKey.RecoverFromSignature(recId, signature, header.GetHash(), true); if (pubKeyForSig == null) { break; } IFederationMember federationMember = federation.FirstOrDefault(m => m.PubKey == pubKeyForSig); if (federationMember != null) { this.minersByBlockHash[chainedHeader.HashBlock] = federationMember; return(federationMember); } } } catch (Exception) { } return(null); }
public void can_always_recover_pubkey_from_signature_when_stopping_at_null() { var rand = new Random(); for (int i = 0; i < 1000; i++) { var key = new Key(); PosBlock block = new PosBlock(new BlockHeader() { Time = (uint)rand.Next() }); ECDSASignature signature = key.Sign(block.GetHash()); block.BlockSignature = new BlockSignature { Signature = signature.ToDER() }; Assert.True(key.PubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature))); signature = ECDSASignature.FromDER(block.BlockSignature.Signature); bool match = false; for (int recId = 0; !match; recId++) { PubKey pubKeyForSig = PubKey.RecoverFromSignature(recId, signature, block.GetHash(), true); if (pubKeyForSig == null) { break; } match = pubKeyForSig == key.PubKey; } Assert.True(match); } }
public override void Run(RuleContext context) { var header = context.ValidationContext.ChainedHeaderToValidate.Header as PoABlockHeader; PubKey pubKey = this.slotsManager.GetFederationMemberForBlock(context.ValidationContext.ChainedHeaderToValidate, this.votingManager).PubKey; if (!this.validator.VerifySignature(pubKey, header)) { if (this.votingEnabled) { ChainedHeader currentHeader = context.ValidationContext.ChainedHeaderToValidate; // If we're evaluating a batch of received headers it's possible that we're so far beyond the current tip // that we have not yet processed all the votes that may determine the federation make-up. bool mightBeInsufficient = currentHeader.Height - this.chainState.ConsensusTip.Height > this.maxReorg; if (mightBeInsufficient) { // Mark header as insufficient to avoid banning the peer that presented it. // When we advance consensus we will be able to validate it. context.ValidationContext.InsufficientHeaderInformation = true; } } try { // Gather all past and present mining public keys. IEnumerable <PubKey> genesisFederation = ((PoAConsensusOptions)this.network.Consensus.Options).GenesisFederationMembers.Select(m => m.PubKey); var knownKeys = new HashSet <PubKey>(genesisFederation); foreach (Poll poll in this.votingManager.GetFinishedPolls().Where(x => ((x.VotingData.Key == VoteKey.AddFederationMember) || (x.VotingData.Key == VoteKey.KickFederationMember)))) { IFederationMember federationMember = ((PoAConsensusFactory)(this.network.Consensus.ConsensusFactory)).DeserializeFederationMember(poll.VotingData.Data); knownKeys.Add(federationMember.PubKey); } // Try to provide the public key that signed the block. var signature = ECDSASignature.FromDER(header.BlockSignature.Signature); for (int recId = 0; recId < 4; recId++) { PubKey pubKeyForSig = PubKey.RecoverFromSignature(recId, signature, header.GetHash(), true); if (pubKeyForSig == null) { this.Logger.LogDebug($"Could not match candidate keys to any known key."); break; } this.Logger.LogDebug($"Attempting to match candidate key '{ pubKeyForSig.ToHex() }' to known keys."); if (!knownKeys.Any(pk => pk == pubKeyForSig)) { continue; } IEnumerable <PubKey> modifiedFederation = this.votingManager?.GetModifiedFederation(context.ValidationContext.ChainedHeaderToValidate).Select(m => m.PubKey) ?? genesisFederation; this.Logger.LogDebug($"Block is signed by '{0}' but expected '{1}' from: {2}.", pubKeyForSig.ToHex(), pubKey, string.Join(" ", modifiedFederation.Select(pk => pk.ToHex()))); break; } ; } catch (Exception) { } this.Logger.LogTrace("(-)[INVALID_SIGNATURE]"); PoAConsensusErrors.InvalidHeaderSignature.Throw(); } }