diff --git a/docs/architecture/adr-008-priv-validator.md b/docs/architecture/adr-008-priv-validator.md new file mode 100644 index 000000000..dfee112c6 --- /dev/null +++ b/docs/architecture/adr-008-priv-validator.md @@ -0,0 +1,118 @@ +# ADR 008: PrivValidator + +## Context + +The current PrivValidator is monolithic and isn't easily reuseable by alternative signers. + +For instance, see https://github.com/tendermint/tendermint/issues/673 + +The goal is to have a clean PrivValidator interface like: + +`` +type PrivValidator interface { + Address() data.Bytes + PubKey() crypto.PubKey + + SignVote(chainID string, vote *types.Vote) error + SignProposal(chainID string, proposal *types.Proposal) error + SignHeartbeat(chainID string, heartbeat *types.Heartbeat) error +} +``` + +It should also be easy to re-use the LastSignedInfo logic to avoid double signing. + +## Decision + +Tendermint node's should support only two in-process PrivValidator implementations: + +- PrivValidatorUnencrypted uses an unencrypted private key in a "priv_validator.json" file - no configuration required (just `tendermint init`). +- PrivValidatorSocket uses a socket to send signing requests to another process - user is responsible for starting that process themselves. + +The PrivValidatorSocket address can be provided via flags at the command line - +doing so will cause Tendermint to ignore any "priv_validator.json" file and to attempt +to connect over the socket. + +In addition, Tendermint will provide implementations that can be run in that external process. +These include: + +- PrivValidatorEncrypted uses an encrypted private key persisted to disk - user must enter password to decrypt key when process is started. +- PrivValidatorLedger uses a Ledger Nano S to handle all signing. + +What follows are descriptions of useful types + +### Signer + +``` +type Signer interface { + Sign(msg []byte) (crypto.Signature, error) +} +``` + +Signer signs a message. It can also return an error. + +### ValidatorID + + +ValidatorID is just the Address and PubKey + +``` +type ValidatorID struct { + Address data.Bytes `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` +} + +### LastSignedInfo + +LastSignedInfo tracks the last thing we signed: + +``` +type LastSignedInfo struct { + Height int64 `json:"height"` + Round int `json:"round"` + Step int8 `json:"step"` + Signature crypto.Signature `json:"signature,omitempty"` // so we dont lose signatures + SignBytes data.Bytes `json:"signbytes,omitempty"` // so we dont lose signatures +} +``` + +It exposes methods for signing votes and proposals using a `Signer`. + +This allows it to easily be reused by developers implemented their own PrivValidator. + +### PrivValidatorUnencrypted + +``` +type PrivValidatorUnencrypted struct { + ID types.ValidatorID `json:"id"` + PrivKey PrivKey `json:"priv_key"` + LastSignedInfo *LastSignedInfo `json:"last_signed_info"` +} +``` + +Has the same structure as currently, but broken up into sub structs. + +Note the LastSignedInfo is mutated in place every time we sign. + +### PrivValidatorJSON + +The "priv_validator.json" file supports only the PrivValidatorUnencrypted type. + +It unmarshals into PrivValidatorJSON, which is used as the default PrivValidator type. +It wraps the PrivValidatorUnencrypted and persists it to disk after every signature. + +## Status + +Proposed. + +## Consequences + +### Positive + +- Cleaner separation of components enabling re-use. + +### Negative + +- More files - led to creation of new directory. + +### Neutral +