github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/verification/staking_signer.go (about)

     1  package verification
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
     7  	"github.com/koko1123/flow-go-1/model/flow"
     8  	"github.com/koko1123/flow-go-1/module"
     9  	msig "github.com/koko1123/flow-go-1/module/signature"
    10  	"github.com/onflow/flow-go/crypto/hash"
    11  )
    12  
    13  // StakingSigner creates votes for the collector clusters consensus.
    14  // When a participant votes for a block, it _always_ provide the staking signature
    15  // as part of their vote. StakingSigner is responsible for creating correctly
    16  // signed proposals and votes.
    17  type StakingSigner struct {
    18  	me            module.Local
    19  	stakingHasher hash.Hasher
    20  	signerID      flow.Identifier
    21  }
    22  
    23  // NewStakingSigner instantiates a StakingSigner, which signs votes and
    24  // proposals with the staking key.  The generated signatures are aggregatable.
    25  func NewStakingSigner(
    26  	me module.Local,
    27  ) *StakingSigner {
    28  
    29  	sc := &StakingSigner{
    30  		me:            me,
    31  		stakingHasher: msig.NewBLSHasher(msig.CollectorVoteTag),
    32  		signerID:      me.NodeID(),
    33  	}
    34  	return sc
    35  }
    36  
    37  // CreateProposal will create a proposal with a staking signature for the given block.
    38  func (c *StakingSigner) CreateProposal(block *model.Block) (*model.Proposal, error) {
    39  
    40  	// check that the block is created by us
    41  	if block.ProposerID != c.signerID {
    42  		return nil, fmt.Errorf("can't create proposal for someone else's block")
    43  	}
    44  
    45  	// create the signature data
    46  	sigData, err := c.genSigData(block)
    47  	if err != nil {
    48  		return nil, fmt.Errorf("signing my proposal failed: %w", err)
    49  	}
    50  
    51  	// create the proposal
    52  	proposal := &model.Proposal{
    53  		Block:   block,
    54  		SigData: sigData,
    55  	}
    56  
    57  	return proposal, nil
    58  }
    59  
    60  // CreateVote will create a vote with a staking signature for the given block.
    61  func (c *StakingSigner) CreateVote(block *model.Block) (*model.Vote, error) {
    62  
    63  	// create the signature data
    64  	sigData, err := c.genSigData(block)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("could not create signature: %w", err)
    67  	}
    68  
    69  	// create the vote
    70  	vote := &model.Vote{
    71  		View:     block.View,
    72  		BlockID:  block.BlockID,
    73  		SignerID: c.signerID,
    74  		SigData:  sigData,
    75  	}
    76  
    77  	return vote, nil
    78  }
    79  
    80  // genSigData generates the signature data for our local node for the given block.
    81  // It returns:
    82  //   - (stakingSig, nil) signature signed with staking key.  The sig is 48 bytes long
    83  //   - (nil, error) if there is any exception
    84  func (c *StakingSigner) genSigData(block *model.Block) ([]byte, error) {
    85  	// create the message to be signed and generate signatures
    86  	msg := MakeVoteMessage(block.View, block.BlockID)
    87  
    88  	stakingSig, err := c.me.Sign(msg, c.stakingHasher)
    89  	if err != nil {
    90  		return nil, fmt.Errorf("could not generate staking signature for block (%v) at view %v: %w", block.BlockID, block.View, err)
    91  	}
    92  
    93  	return stakingSig, nil
    94  }