Skip to content

Commit

Permalink
abi encoded signature
Browse files Browse the repository at this point in the history
  • Loading branch information
blasrodri committed Mar 21, 2024
1 parent 07493f4 commit f49fca0
Show file tree
Hide file tree
Showing 11 changed files with 702 additions and 114 deletions.
2 changes: 1 addition & 1 deletion cmd/cometbft/commands/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func testnetFiles(cmd *cobra.Command, args []string) error {

pvKeyFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorKey)
pvStateFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorState)
pv := privval.LoadFilePV(pvKeyFile, pvStateFile)
pv := privval.LoadFilePV(pvKeyFile, pvStateFile, "/tmp/asd") //TODO(blas): change

pubKey, err := pv.GetPubKey()
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2280,6 +2280,11 @@ func (cs *State) signVote(

v := vote.ToProto()
err := cs.privValidator.SignVote(cs.state.ChainID, v)
if err != nil {
return vote, err
}
vAbiEncoded := []byte{}
err = cs.privValidator.SignVoteAbiEncoded(cs.state.ChainID, vAbiEncoded)
vote.Signature = v.Signature
vote.Timestamp = v.Timestamp

Expand Down
410 changes: 410 additions & 0 deletions go.work.sum

Large diffs are not rendered by default.

73 changes: 60 additions & 13 deletions privval/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,13 @@ func (lss *FilePVLastSignState) Save() {
// It includes the LastSignature and LastSignBytes so we don't lose the signature
// if the process crashes after signing but before the resulting consensus message is processed.
type FilePV struct {
Key FilePVKey
LastSignState FilePVLastSignState
Key FilePVKey
LastSignState FilePVLastSignState
LastSignStateAbiEncoded FilePVLastSignState
}

// NewFilePV generates a new validator from the given key and paths.
func NewFilePV(privKey crypto.PrivKey, keyFilePath, stateFilePath string) *FilePV {
func NewFilePV(privKey crypto.PrivKey, keyFilePath, stateFilePath string, stateFilePathAbiEncoded string) *FilePV {
return &FilePV{
Key: FilePVKey{
Address: privKey.PubKey().Address(),
Expand All @@ -164,30 +165,34 @@ func NewFilePV(privKey crypto.PrivKey, keyFilePath, stateFilePath string) *FileP
Step: stepNone,
filePath: stateFilePath,
},
LastSignStateAbiEncoded: FilePVLastSignState{
Step: stepNone,
filePath: stateFilePathAbiEncoded,
},
}
}

// GenFilePV generates a new validator with randomly generated private key
// and sets the filePaths, but does not call Save().
func GenFilePV(keyFilePath, stateFilePath string) *FilePV {
return NewFilePV(ed25519.GenPrivKey(), keyFilePath, stateFilePath)
func GenFilePV(keyFilePath, stateFilePath string, stateFilePathAbiEncoded string) *FilePV {
return NewFilePV(ed25519.GenPrivKey(), keyFilePath, stateFilePath, stateFilePathAbiEncoded)
}

// LoadFilePV loads a FilePV from the filePaths. The FilePV handles double
// signing prevention by persisting data to the stateFilePath. If either file path
// does not exist, the program will exit.
func LoadFilePV(keyFilePath, stateFilePath string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, true)
func LoadFilePV(keyFilePath, stateFilePath string, stateFilePathAbiEncoded string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, stateFilePathAbiEncoded, true)
}

// LoadFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState.
// If the keyFilePath does not exist, the program will exit.
func LoadFilePVEmptyState(keyFilePath, stateFilePath string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, false)
func LoadFilePVEmptyState(keyFilePath, stateFilePath string, stateFilePathAbiEncoded string) *FilePV {
return loadFilePV(keyFilePath, stateFilePath, stateFilePathAbiEncoded, false)
}

// If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState.
func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {
func loadFilePV(keyFilePath, stateFilePath string, stateFilePathAbiEncoded string, loadState bool) *FilePV {
keyJSONBytes, err := os.ReadFile(keyFilePath)
if err != nil {
cmtos.Exit(err.Error())
Expand Down Expand Up @@ -226,12 +231,12 @@ func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {

// LoadOrGenFilePV loads a FilePV from the given filePaths
// or else generates a new one and saves it to the filePaths.
func LoadOrGenFilePV(keyFilePath, stateFilePath string) *FilePV {
func LoadOrGenFilePV(keyFilePath, stateFilePath string, stateFilePathAbiEncoded string) *FilePV {
var pv *FilePV
if cmtos.FileExists(keyFilePath) {
pv = LoadFilePV(keyFilePath, stateFilePath)
pv = LoadFilePV(keyFilePath, stateFilePath, stateFilePathAbiEncoded)
} else {
pv = GenFilePV(keyFilePath, stateFilePath)
pv = GenFilePV(keyFilePath, stateFilePath, stateFilePathAbiEncoded)
pv.Save()
}
return pv
Expand Down Expand Up @@ -340,6 +345,48 @@ func (pv *FilePV) signVote(chainID string, vote *cmtproto.Vote) error {
return nil
}

// signVote checks if the vote is good to sign and sets the vote signature.
// It may need to set the timestamp as well if the vote is otherwise the same as
// a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
func (pv *FilePV) signVoteAbiEncoded(chainID string, vote *cmtproto.Vote) error {
height, round, step := vote.Height, vote.Round, voteToStep(vote)

lss := pv.LastSignState

sameHRS, err := lss.CheckHRS(height, round, step)
if err != nil {
return err
}

signBytes := types.VoteSignBytesAbiEncoded(chainID, vote)

Check failure on line 361 in privval/file.go

View workflow job for this annotation

GitHub Actions / govulncheck

cannot use vote (variable of type *"github.com/cometbft/cometbft/proto/tendermint/types".Vote) as []byte value in argument to types.VoteSignBytesAbiEncoded

// We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS.
// If signbytes are the same, use the last signature.
// If they only differ by timestamp, use last timestamp and signature
// Otherwise, return error
if sameHRS {
if bytes.Equal(signBytes, lss.SignBytes) {
vote.Signature = lss.Signature
} else if timestamp, ok := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes); ok {
vote.Timestamp = timestamp
vote.Signature = lss.Signature
} else {
err = fmt.Errorf("conflicting data")
}
return err
}

// It passed the checks. Sign the vote
sig, err := pv.Key.PrivKey.Sign(signBytes)
if err != nil {
return err
}
pv.saveSigned(height, round, step, signBytes, sig)
vote.Signature = sig
return nil
}

// signProposal checks if the proposal is good to sign and sets the proposal signature.
// It may need to set the timestamp as well if the proposal is otherwise the same as
// a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL).
Expand Down
32 changes: 24 additions & 8 deletions privval/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ func TestGenLoadValidator(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())

height := int64(100)
privVal.LastSignState.Height = height
privVal.Save()
addr := privVal.GetAddress()

privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved")
}
Expand All @@ -44,8 +46,10 @@ func TestResetValidator(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())
emptyState := FilePVLastSignState{filePath: tempStateFile.Name()}

// new priv val has empty state
Expand Down Expand Up @@ -75,6 +79,8 @@ func TestLoadOrGenValidator(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

tempKeyFilePath := tempKeyFile.Name()
if err := os.Remove(tempKeyFilePath); err != nil {
Expand All @@ -84,10 +90,14 @@ func TestLoadOrGenValidator(t *testing.T) {
if err := os.Remove(tempStateFilePath); err != nil {
t.Error(err)
}
tempStateFileAbiEncodedPath := tempStateFileAbiEncodedFile.Name()
if err := os.Remove(tempStateFileAbiEncodedPath); err != nil {
t.Error(err)
}

privVal := LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
privVal := LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath, tempStateFileAbiEncodedPath)
addr := privVal.GetAddress()
privVal = LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath)
privVal = LoadOrGenFilePV(tempKeyFilePath, tempStateFilePath, tempStateFileAbiEncodedPath)
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
}

Expand Down Expand Up @@ -162,8 +172,10 @@ func TestSignVote(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())

randbytes := cmtrand.Bytes(tmhash.Size)
randbytes2 := cmtrand.Bytes(tmhash.Size)
Expand Down Expand Up @@ -215,8 +227,10 @@ func TestSignProposal(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())

randbytes := cmtrand.Bytes(tmhash.Size)
randbytes2 := cmtrand.Bytes(tmhash.Size)
Expand Down Expand Up @@ -263,8 +277,10 @@ func TestDifferByTimestamp(t *testing.T) {
require.Nil(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
require.Nil(t, err)
tempStateFileAbiEncodedFile, err := os.CreateTemp("", "priv_validator_state_abi_encoded")
require.Nil(t, err)

privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), tempStateFileAbiEncodedFile.Name())
randbytes := cmtrand.Bytes(tmhash.Size)
block1 := types.BlockID{Hash: randbytes, PartSetHeader: types.PartSetHeader{Total: 5, Hash: randbytes}}
height, round := int64(10), int32(1)
Expand Down
16 changes: 16 additions & 0 deletions privval/retry_signer_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ func (sc *RetrySignerClient) SignVote(chainID string, vote *cmtproto.Vote) error
return fmt.Errorf("exhausted all attempts to sign vote: %w", err)
}

func (sc *RetrySignerClient) SignVoteAbiEncoded(chainID string, vote []byte) error {
var err error
for i := 0; i < sc.retries || sc.retries == 0; i++ {
err = sc.next.SignVoteAbiEncoded(chainID, vote)
if err == nil {
return nil
}
// If remote signer errors, we don't retry.
if _, ok := err.(*RemoteSignerError); ok {
return err
}
time.Sleep(sc.timeout)
}
return fmt.Errorf("exhausted all attempts to sign vote: %w", err)
}

func (sc *RetrySignerClient) SignProposal(chainID string, proposal *cmtproto.Proposal) error {
var err error
for i := 0; i < sc.retries || sc.retries == 0; i++ {
Expand Down
6 changes: 6 additions & 0 deletions privval/signer_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ func (sc *SignerClient) SignVote(chainID string, vote *cmtproto.Vote) error {
return nil
}

// SignVote requests a remote signer to sign a vote
func (sc *SignerClient) SignVoteAbiEncoded(chainID string, vote []byte) error {
//TODO(blas): implement
return nil
}

// SignProposal requests a remote signer to sign a proposal
func (sc *SignerClient) SignProposal(chainID string, proposal *cmtproto.Proposal) error {
response, err := sc.endpoint.SendRequest(mustWrapMsg(
Expand Down
Loading

0 comments on commit f49fca0

Please sign in to comment.