// Verify that +2/3 of the set had signed the given signBytes func (valSet *ValidatorSet) VerifyValidation(chainID string, hash []byte, parts PartSetHeader, height int, v *Validation) error { if valSet.Size() != len(v.Precommits) { return fmt.Errorf("Invalid validation -- wrong set size: %v vs %v", valSet.Size(), len(v.Precommits)) } if height != v.Height() { return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, v.Height()) } talliedVotingPower := int64(0) round := v.Round() for idx, precommit := range v.Precommits { // may be nil if validator skipped. if precommit == nil { continue } if precommit.Height != height { return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, precommit.Height) } if precommit.Round != round { return fmt.Errorf("Invalid validation -- wrong round: %v vs %v", round, precommit.Round) } if precommit.Type != VoteTypePrecommit { return fmt.Errorf("Invalid validation -- not precommit @ index %v", idx) } _, val := valSet.GetByIndex(idx) // Validate signature precommitSignBytes := account.SignBytes(chainID, precommit) if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) { return fmt.Errorf("Invalid validation -- invalid signature: %v", precommit) } if !bytes.Equal(precommit.BlockHash, hash) { continue // Not an error, but doesn't count } if !parts.Equals(precommit.BlockPartsHeader) { continue // Not an error, but doesn't count } // Good precommit! talliedVotingPower += val.VotingPower } if talliedVotingPower > valSet.TotalVotingPower()*2/3 { return nil } else { return fmt.Errorf("Invalid validation -- insufficient voting power: got %v, needed %v", talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1)) } }
func (voteSet *VoteSet) addVote(val *Validator, valIndex int, vote *Vote) (bool, int, error) { // Make sure the step matches. (or that vote is commit && round < voteSet.round) if (vote.Height != voteSet.height) || (vote.Round != voteSet.round) || (vote.Type != voteSet.type_) { return false, 0, ErrVoteUnexpectedStep } // Check signature. if !val.PubKey.VerifyBytes(acm.SignBytes(config.GetString("chain_id"), vote), vote.Signature) { // Bad signature. return false, 0, ErrVoteInvalidSignature } // If vote already exists, return false. if existingVote := voteSet.votes[valIndex]; existingVote != nil { if bytes.Equal(existingVote.BlockHash, vote.BlockHash) { return false, valIndex, nil } else { return false, valIndex, &ErrVoteConflictingSignature{ VoteA: existingVote, VoteB: vote, } } } // Add vote. voteSet.votes[valIndex] = vote voteSet.votesBitArray.SetIndex(valIndex, true) blockKey := string(vote.BlockHash) + string(wire.BinaryBytes(vote.BlockPartsHeader)) totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower voteSet.votesByBlock[blockKey] = totalBlockHashVotes voteSet.totalVotes += val.VotingPower // If we just nudged it up to two thirds majority, add it. if totalBlockHashVotes > voteSet.valSet.TotalVotingPower()*2/3 && (totalBlockHashVotes-val.VotingPower) <= voteSet.valSet.TotalVotingPower()*2/3 { voteSet.maj23Hash = vote.BlockHash voteSet.maj23PartsHeader = vote.BlockPartsHeader voteSet.maj23Exists = true } return true, valIndex, nil }
func (privVal *PrivValidator) SignRebondTx(chainID string, rebondTx *RebondTx) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() if privVal.LastHeight < rebondTx.Height { // Persist height/round/step // Prevent doing anything else for this rebondTx.Height. privVal.LastHeight = rebondTx.Height privVal.LastRound = math.MaxInt32 // MaxInt64 overflows on 32bit architectures. privVal.LastStep = math.MaxInt8 privVal.save() // Sign rebondTx.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, rebondTx)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height)) } }
func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error { privVal.mtx.Lock() defer privVal.mtx.Unlock() if privVal.LastHeight < proposal.Height || privVal.LastHeight == proposal.Height && privVal.LastRound < proposal.Round || privVal.LastHeight == 0 && privVal.LastRound == 0 && privVal.LastStep == stepNone { // Persist height/round/step privVal.LastHeight = proposal.Height privVal.LastRound = proposal.Round privVal.LastStep = stepPropose privVal.save() // Sign proposal.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, proposal)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v", proposal.Height, proposal.Round)) } }
// tx has either one input or we default to the first one (ie for send/bond) // TODO: better support for multisig and bonding func signTx(signAddr, chainID string, tx_ types.Tx) ([]byte, types.Tx, error) { signBytes := fmt.Sprintf("%X", account.SignBytes(chainID, tx_)) var inputAddr []byte var sigED account.SignatureEd25519 switch tx := tx_.(type) { case *types.SendTx: inputAddr = tx.Inputs[0].Address defer func(s *account.SignatureEd25519) { tx.Inputs[0].Signature = *s }(&sigED) case *types.NameTx: inputAddr = tx.Input.Address defer func(s *account.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) case *types.CallTx: inputAddr = tx.Input.Address defer func(s *account.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) case *types.PermissionsTx: inputAddr = tx.Input.Address defer func(s *account.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) case *types.BondTx: inputAddr = tx.Inputs[0].Address defer func(s *account.SignatureEd25519) { tx.Signature = *s tx.Inputs[0].Signature = *s }(&sigED) case *types.UnbondTx: inputAddr = tx.Address defer func(s *account.SignatureEd25519) { tx.Signature = *s }(&sigED) case *types.RebondTx: inputAddr = tx.Address defer func(s *account.SignatureEd25519) { tx.Signature = *s }(&sigED) } addrHex := fmt.Sprintf("%X", inputAddr) sig, err := Sign(signBytes, addrHex, signAddr) if err != nil { return nil, nil, err } sigED = account.SignatureEd25519(sig) logger.Debugf("SIG: %X\n", sig) return inputAddr, tx_, nil }
func (privVal *PrivValidator) SignVoteUnsafe(chainID string, vote *Vote) { vote.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, vote)).(acm.SignatureEd25519) }
// This should match the leaf hashes of Block.Data.Hash()'s SimpleMerkleTree. func TxID(chainID string, tx Tx) []byte { signBytes := acm.SignBytes(chainID, tx) return wire.BinaryRipemd160(signBytes) }