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

abi encoded signature #4

Draft
wants to merge 1 commit into
base: version-0.37.5
Choose a base branch
from
Draft
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
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 @@
// 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 @@
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 @@

// 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 @@
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
Loading