Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VE extension patch #7

Merged
merged 19 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
620 changes: 419 additions & 201 deletions abci/types/types.pb.go

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions consensus/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func (vs *validatorStub) signVote(
hash []byte,
header types.PartSetHeader,
voteExtension []byte,
nonRpVoteExtension []byte,
extEnabled bool,
) (*types.Vote, error) {
pubKey, err := vs.PrivValidator.GetPubKey()
Expand All @@ -107,6 +108,7 @@ func (vs *validatorStub) signVote(
ValidatorAddress: pubKey.Address(),
ValidatorIndex: vs.Index,
Extension: voteExtension,
NonRpExtension: nonRpVoteExtension,
}
v := vote.ToProto()
if err = vs.PrivValidator.SignVote(test.DefaultTestChainID, v); err != nil {
Expand All @@ -118,32 +120,36 @@ func (vs *validatorStub) signVote(
v.Signature = vs.lastVote.Signature
v.Timestamp = vs.lastVote.Timestamp
v.ExtensionSignature = vs.lastVote.ExtensionSignature
v.NonRpExtensionSignature = vs.lastVote.NonRpExtensionSignature
}

vote.Signature = v.Signature
vote.Timestamp = v.Timestamp
vote.ExtensionSignature = v.ExtensionSignature
vote.NonRpExtensionSignature = v.NonRpExtensionSignature

if !extEnabled {
vote.ExtensionSignature = nil
vote.NonRpExtensionSignature = nil
}

return vote, err
}

// Sign vote for type/hash/header
func signVote(vs *validatorStub, voteType cmtproto.SignedMsgType, hash []byte, header types.PartSetHeader, extEnabled bool) *types.Vote {
var ext []byte
var ext, nonRpExt []byte
// Only non-nil precommits are allowed to carry vote extensions.
if extEnabled {
if voteType != cmtproto.PrecommitType {
panic(fmt.Errorf("vote type is not precommit but extensions enabled"))
}
if len(hash) != 0 || !header.IsZero() {
ext = []byte("extension")
nonRpExt = []byte("non_replay_protected_extension")
}
}
v, err := vs.signVote(voteType, hash, header, ext, extEnabled)
v, err := vs.signVote(voteType, hash, header, ext, nonRpExt, extEnabled)

if err != nil {
panic(fmt.Errorf("failed to sign vote: %v", err))
Expand Down Expand Up @@ -987,5 +993,6 @@ func signDataIsEqual(v1 *types.Vote, v2 *cmtproto.Vote) bool {
v1.Round == v2.Round &&
bytes.Equal(v1.ValidatorAddress.Bytes(), v2.GetValidatorAddress()) &&
v1.ValidatorIndex == v2.GetValidatorIndex() &&
bytes.Equal(v1.Extension, v2.Extension)
bytes.Equal(v1.Extension, v2.Extension) &&
bytes.Equal(v1.NonRpExtension, v2.NonRpExtension)
}
2 changes: 2 additions & 0 deletions consensus/invalid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ func invalidDoPrevoteFunc(t *testing.T, cs *State, sw *p2p.Switch, pv types.Priv
}
precommit.Signature = p.Signature
precommit.ExtensionSignature = p.ExtensionSignature
precommit.NonRpExtension = p.NonRpExtension
precommit.NonRpExtensionSignature = p.NonRpExtensionSignature
cs.privValidator = nil // disable priv val so we don't do normal votes

peers := sw.Peers().List()
Expand Down
1 change: 1 addition & 0 deletions consensus/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ func TestConsMsgsVectors(t *testing.T) {
}
vpb := v.ToProto()
v.Extension = []byte("extension")
// TODO bernd: extend test to cover v.NonRpExtension
vextPb := v.ToProto()

testCases := []struct {
Expand Down
3 changes: 3 additions & 0 deletions consensus/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,13 @@ func TestSwitchToConsensusVoteExtensions(t *testing.T) {
var veHeight int64
if testCase.includeExtensions {
require.NotNil(t, signedVote.ExtensionSignature)
require.NotNil(t, signedVote.NonRpExtensionSignature)
veHeight = testCase.storedHeight
} else {
require.Nil(t, signedVote.Extension)
require.Nil(t, signedVote.ExtensionSignature)
require.Nil(t, signedVote.NonRpExtension)
require.Nil(t, signedVote.NonRpExtensionSignature)
}

added, err := voteSet.AddVote(signedVote)
Expand Down
4 changes: 3 additions & 1 deletion consensus/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ func (cs *State) readReplayMessage(msg *TimedWALMessage, newStepSub types.Subscr
case *VoteMessage:
v := msg.Vote
cs.Logger.Info("Replay: Vote", "height", v.Height, "round", v.Round, "type", v.Type,
"blockID", v.BlockID, "peer", peerID, "extensionLen", len(v.Extension), "extSigLen", len(v.ExtensionSignature))
"blockID", v.BlockID, "peer", peerID,
"extensionLen", len(v.Extension), "extSigLen", len(v.ExtensionSignature),
"nrp-extensionLen", len(v.NonRpExtension), "nrp-extSigLen", len(v.NonRpExtensionSignature))
}

cs.handleMsg(m)
Expand Down
8 changes: 6 additions & 2 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2123,6 +2123,8 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
"cs_height", cs.Height,
"extLen", len(vote.Extension),
"extSigLen", len(vote.ExtensionSignature),
"nrpExtLen", len(vote.NonRpExtension),
"nrpExtSigLen", len(vote.NonRpExtensionSignature),
)

if vote.Height < cs.Height || (vote.Height == cs.Height && vote.Round < cs.Round) {
Expand Down Expand Up @@ -2217,7 +2219,8 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
// TODO punish a peer if it sent a vote with an extension when the feature
// is disabled on the network.
// https://github.com/tendermint/tendermint/issues/8565
if len(vote.Extension) > 0 || len(vote.ExtensionSignature) > 0 {
if len(vote.Extension) > 0 || len(vote.ExtensionSignature) > 0 ||
len(vote.NonRpExtension) > 0 || len(vote.NonRpExtensionSignature) > 0 {
return false, fmt.Errorf("received vote with vote extension for height %v (extensions disabled) from peer ID %s", vote.Height, peerID)
}
}
Expand Down Expand Up @@ -2394,11 +2397,12 @@ func (cs *State) signVote(
// if the signedMessage type is for a non-nil precommit, add
// VoteExtension
if extEnabled {
ext, err := cs.blockExec.ExtendVote(context.TODO(), vote, block, cs.state)
ext, nonRpExt, err := cs.blockExec.ExtendVote(context.TODO(), vote, block, cs.state)
if err != nil {
return nil, err
}
vote.Extension = ext
vote.NonRpExtension = nonRpExt
}
}

Expand Down
39 changes: 26 additions & 13 deletions consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1564,10 +1564,11 @@ func TestExtendVoteCalledWhenEnabled(t *testing.T) {
addr := pv.Address()
if testCase.enabled {
m.AssertCalled(t, "VerifyVoteExtension", context.TODO(), &abci.RequestVerifyVoteExtension{
Hash: blockID.Hash,
ValidatorAddress: addr,
Height: height,
VoteExtension: []byte("extension"),
Hash: blockID.Hash,
ValidatorAddress: addr,
Height: height,
VoteExtension: []byte("extension"),
NonRpVoteExtension: []byte("non_replay_protected_extension"),
})
} else {
m.AssertNotCalled(t, "VerifyVoteExtension", mock.Anything, mock.Anything)
Expand Down Expand Up @@ -1638,10 +1639,11 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) {
addr = pv.Address()

m.AssertNotCalled(t, "VerifyVoteExtension", context.TODO(), &abci.RequestVerifyVoteExtension{
Hash: blockID.Hash,
ValidatorAddress: addr,
Height: height,
VoteExtension: []byte("extension"),
Hash: blockID.Hash,
ValidatorAddress: addr,
Height: height,
VoteExtension: []byte("extension"),
NonRpVoteExtension: []byte("non_replay_protected_extension"),
})
}

Expand All @@ -1659,10 +1661,17 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) {
[]byte("extension 2"),
[]byte("extension 3"),
}
nonRpVoteExtensions := [][]byte{
[]byte("nrp-extension 0"),
[]byte("nrp-extension 1"),
[]byte("nrp-extension 2"),
[]byte("nrp-extension 3"),
}

m := abcimocks.NewApplication(t)
m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{
VoteExtension: voteExtensions[0],
VoteExtension: voteExtensions[0],
NonRpExtension: nonRpVoteExtensions[0],
}, nil)
m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil)

Expand Down Expand Up @@ -1700,7 +1709,8 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) {

// create a precommit for each validator with the associated vote extension.
for i, vs := range vss[1:] {
signAddPrecommitWithExtension(t, cs1, blockID.Hash, blockID.PartSetHeader, voteExtensions[i+1], vs)
signAddPrecommitWithExtension(t, cs1, blockID.Hash, blockID.PartSetHeader,
voteExtensions[i+1], nonRpVoteExtensions[i+1], vs)
}

ensurePrevote(voteCh, height, round)
Expand Down Expand Up @@ -1728,6 +1738,7 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) {
for i := range vss {
vote := &rpp.LocalLastCommit.Votes[i]
require.Equal(t, vote.VoteExtension, voteExtensions[i])
require.Equal(t, vote.NonRpVoteExtension, nonRpVoteExtensions[i])

require.NotZero(t, len(vote.ExtensionSignature))
cve := cmtproto.CanonicalVoteExtension{
Expand Down Expand Up @@ -1915,13 +1926,14 @@ func TestVoteExtensionEnableHeight(t *testing.T) {
signAddVotes(cs1, cmtproto.PrevoteType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), false, vss[1:]...)
ensurePrevoteMatch(t, voteCh, height, round, rs.ProposalBlock.Hash())

var ext []byte
var ext, nonRpExt []byte
if testCase.hasExtension {
ext = []byte("extension")
nonRpExt = []byte("non_replay_protected_extension")
}

for _, vs := range vss[1:] {
vote, err := vs.signVote(cmtproto.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), ext, testCase.hasExtension)
vote, err := vs.signVote(cmtproto.PrecommitType, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), ext, nonRpExt, testCase.hasExtension)
require.NoError(t, err)
addVotes(cs1, vote)
}
Expand Down Expand Up @@ -2582,9 +2594,10 @@ func signAddPrecommitWithExtension(
hash []byte,
header types.PartSetHeader,
extension []byte,
nonRpExtension []byte,
stub *validatorStub,
) {
v, err := stub.signVote(cmtproto.PrecommitType, hash, header, extension, true)
v, err := stub.signVote(cmtproto.PrecommitType, hash, header, extension, nonRpExtension, true)
require.NoError(t, err, "failed to sign vote")
addVotes(cs, v)
}
Expand Down
1 change: 1 addition & 0 deletions consensus/types/height_vote_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func TestInconsistentExtensionData(t *testing.T) {
hvsE := NewExtendedHeightVoteSet(test.DefaultTestChainID, 1, valSet)
voteNoExt := makeVoteHR(1, 0, 20, privVals)
voteNoExt.Extension, voteNoExt.ExtensionSignature = nil, nil
voteNoExt.NonRpExtension, voteNoExt.NonRpExtensionSignature = nil, nil
require.Panics(t, func() {
_, _ = hvsE.AddVote(voteNoExt, "peer1", false)
})
Expand Down
3 changes: 2 additions & 1 deletion evidence/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,8 @@ func makeExtCommit(height int64, valAddr []byte) *types.ExtendedCommit {
Timestamp: defaultEvidenceTime,
Signature: []byte("Signature"),
},
ExtensionSignature: []byte("Extended Signature"),
ExtensionSignature: []byte("Extended Signature"),
NonRpExtensionSignature: []byte("Non Replay Protected Extended Signature"),
}},
}
}
Expand Down
8 changes: 6 additions & 2 deletions light/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,17 @@ func makeVote(header *types.Header, valset *types.ValidatorSet,
}
vote.Signature = sig

extSignBytes := types.VoteExtensionSignBytes(header.ChainID, v)
extSignBytes, nonRpExtSignBytes := types.VoteExtensionSignBytes(header.ChainID, v)
extSig, err := key.Sign(extSignBytes)
if err != nil {
panic(err)
}
nonRpExtSig, err := key.Sign(nonRpExtSignBytes)
if err != nil {
panic(err)
}
vote.ExtensionSignature = extSig

vote.NonRpExtensionSignature = nonRpExtSig
return vote
}

Expand Down
11 changes: 9 additions & 2 deletions privval/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,18 @@ func (pv *FilePV) signVote(chainID string, vote *cmtproto.Vote) error {
// precommits, the extension signature will always be empty.
// Even if the signed over data is empty, we still add the signature
var extSig []byte
var nonRpExtSig []byte
if vote.Type == cmtproto.PrecommitType && !types.ProtoBlockIDIsNil(&vote.BlockID) {
extSignBytes := types.VoteExtensionSignBytes(chainID, vote)
extSignBytes, nonRpExtSignBytes := types.VoteExtensionSignBytes(chainID, vote)
extSig, err = pv.Key.PrivKey.Sign(extSignBytes)
if err != nil {
return err
}
} else if len(vote.Extension) > 0 {
nonRpExtSig, err = pv.Key.PrivKey.Sign(nonRpExtSignBytes)
if err != nil {
return err
}
} else if len(vote.Extension) > 0 || len(vote.NonRpExtension) > 0 {
return errors.New("unexpected vote extension - extensions are only allowed in non-nil precommits")
}

Expand All @@ -351,6 +356,7 @@ func (pv *FilePV) signVote(chainID string, vote *cmtproto.Vote) error {
}

vote.ExtensionSignature = extSig
vote.NonRpExtensionSignature = nonRpExtSig

return err
}
Expand All @@ -363,6 +369,7 @@ func (pv *FilePV) signVote(chainID string, vote *cmtproto.Vote) error {
pv.saveSigned(height, round, step, signBytes, sig)
vote.Signature = sig
vote.ExtensionSignature = extSig
vote.NonRpExtensionSignature = nonRpExtSig

return nil
}
Expand Down
Loading
Loading