From 8ae2ffda8984e7b8d693521bfa7de907e141b7a6 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Sep 2017 16:58:18 -0400 Subject: [PATCH] put funcs back in order to simplify review --- config/toml.go | 24 ++-- types/priv_validator.go | 268 ++++++++++++++++++++-------------------- 2 files changed, 144 insertions(+), 148 deletions(-) diff --git a/config/toml.go b/config/toml.go index 4366695d..5dcbe533 100644 --- a/config/toml.go +++ b/config/toml.go @@ -127,16 +127,16 @@ var testGenesis = `{ }` var testPrivValidator = `{ - "address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456", - "pub_key": { - "type": "ed25519", - "data": "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" - }, - "priv_key": { - "type": "ed25519", - "data": "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" - }, - "last_height": 0, - "last_round": 0, - "last_step": 0 + "address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456", + "pub_key": { + "type": "ed25519", + "data": "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" + }, + "priv_key": { + "type": "ed25519", + "data": "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" + }, + "last_height": 0, + "last_round": 0, + "last_step": 0 }` diff --git a/types/priv_validator.go b/types/priv_validator.go index 6db24096..4357c6f3 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -67,6 +67,32 @@ type PrivValidatorFS struct { mtx sync.Mutex } +// Signer is an interface that defines how to sign messages. +// It is the caller's duty to verify the msg before calling Sign, +// eg. to avoid double signing. +// Currently, the only callers are SignVote, SignProposal, and SignHeartbeat. +type Signer interface { + Sign(msg []byte) (crypto.Signature, error) +} + +// DefaultSigner implements Signer. +// It uses a standard, unencrypted crypto.PrivKey. +type DefaultSigner struct { + PrivKey crypto.PrivKey `json:"priv_key"` +} + +// NewDefaultSigner returns an instance of DefaultSigner. +func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner { + return &DefaultSigner{ + PrivKey: priv, + } +} + +// Sign implements Signer. It signs the byte slice with a private key. +func (ds *DefaultSigner) Sign(msg []byte) (crypto.Signature, error) { + return ds.PrivKey.Sign(msg), nil +} + // GetAddress returns the address of the validator. // Implements PrivValidator. func (pv *PrivValidatorFS) GetAddress() data.Bytes { @@ -79,6 +105,104 @@ func (pv *PrivValidatorFS) GetPubKey() crypto.PubKey { return pv.PubKey } +// GenPrivValidatorFS generates a new validator with randomly generated private key +// and sets the filePath, but does not call Save(). +func GenPrivValidatorFS(filePath string) *PrivValidatorFS { + privKey := crypto.GenPrivKeyEd25519().Wrap() + return &PrivValidatorFS{ + Address: privKey.PubKey().Address(), + PubKey: privKey.PubKey(), + PrivKey: privKey, + LastStep: stepNone, + Signer: NewDefaultSigner(privKey), + filePath: filePath, + } +} + +// LoadPrivValidatorFS loads a PrivValidatorFS from the filePath. +func LoadPrivValidatorFS(filePath string) *PrivValidatorFS { + privValJSONBytes, err := ioutil.ReadFile(filePath) + if err != nil { + cmn.Exit(err.Error()) + } + privVal := PrivValidatorFS{} + err = json.Unmarshal(privValJSONBytes, &privVal) + if err != nil { + cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) + } + + privVal.filePath = filePath + privVal.Signer = NewDefaultSigner(privVal.PrivKey) + return &privVal +} + +// LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath +// or else generates a new one and saves it to the filePath. +func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS { + var PrivValidatorFS *PrivValidatorFS + if _, err := os.Stat(filePath); err == nil { + PrivValidatorFS = LoadPrivValidatorFS(filePath) + } else { + PrivValidatorFS = GenPrivValidatorFS(filePath) + PrivValidatorFS.Save() + } + return PrivValidatorFS +} + +// LoadPrivValidatorWithSigner loads a PrivValidatorFS with a custom +// signer object. The PrivValidatorFS handles double signing prevention by persisting +// data to the filePath, while the Signer handles the signing. +// If the filePath does not exist, the PrivValidatorFS must be created manually and saved. +func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(crypto.PubKey) Signer) *PrivValidatorFS { + privValJSONBytes, err := ioutil.ReadFile(filePath) + if err != nil { + cmn.Exit(err.Error()) + } + privVal := PrivValidatorFS{} + err = json.Unmarshal(privValJSONBytes, &privVal) + if err != nil { + cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) + } + + privVal.filePath = filePath + privVal.Signer = signerFunc(privVal.PubKey) + return &privVal +} + +// Save persists the PrivValidatorFS to disk. +func (privVal *PrivValidatorFS) Save() { + privVal.mtx.Lock() + defer privVal.mtx.Unlock() + privVal.save() +} + +func (privVal *PrivValidatorFS) save() { + if privVal.filePath == "" { + cmn.PanicSanity("Cannot save PrivValidator: filePath not set") + } + jsonBytes, err := json.Marshal(privVal) + if err != nil { + // `@; BOOM!!! + cmn.PanicCrisis(err) + } + err = cmn.WriteFileAtomic(privVal.filePath, jsonBytes, 0600) + if err != nil { + // `@; BOOM!!! + cmn.PanicCrisis(err) + } +} + +// Reset resets all fields in the PrivValidatorFS. +// NOTE: Unsafe! +func (privVal *PrivValidatorFS) Reset() { + privVal.LastHeight = 0 + privVal.LastRound = 0 + privVal.LastStep = 0 + privVal.LastSignature = crypto.Signature{} + privVal.LastSignBytes = nil + privVal.Save() +} + // SignVote signs a canonical representation of the vote, along with the chainID. // Implements PrivValidator. func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error { @@ -105,39 +229,6 @@ func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) return nil } -// SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID. -// Implements PrivValidator. -func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error { - privVal.mtx.Lock() - defer privVal.mtx.Unlock() - var err error - heartbeat.Signature, err = privVal.Signer.Sign(SignBytes(chainID, heartbeat)) - return err -} - -// Save persists the PrivValidatorFS to disk. -func (privVal *PrivValidatorFS) Save() { - privVal.mtx.Lock() - defer privVal.mtx.Unlock() - privVal.save() -} - -func (privVal *PrivValidatorFS) save() { - if privVal.filePath == "" { - cmn.PanicSanity("Cannot save PrivValidator: filePath not set") - } - jsonBytes, err := json.Marshal(privVal) - if err != nil { - // `@; BOOM!!! - cmn.PanicCrisis(err) - } - err = cmn.WriteFileAtomic(privVal.filePath, jsonBytes, 0600) - if err != nil { - // `@; BOOM!!! - cmn.PanicCrisis(err) - } -} - // signBytesHRS signs the given signBytes if the height/round/step (HRS) // are greater than the latest state. If the HRS are equal, // it returns the privValidator.LastSignature. @@ -193,15 +284,14 @@ func (privVal *PrivValidatorFS) signBytesHRS(height, round int, step int8, signB return sig, nil } -// Reset resets all fields in the PrivValidatorFS. -// NOTE: Unsafe! -func (privVal *PrivValidatorFS) Reset() { - privVal.LastHeight = 0 - privVal.LastRound = 0 - privVal.LastStep = 0 - privVal.LastSignature = crypto.Signature{} - privVal.LastSignBytes = nil - privVal.Save() +// SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID. +// Implements PrivValidator. +func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error { + privVal.mtx.Lock() + defer privVal.mtx.Unlock() + var err error + heartbeat.Signature, err = privVal.Signer.Sign(SignBytes(chainID, heartbeat)) + return err } // String returns a string representation of the PrivValidatorFS. @@ -209,100 +299,6 @@ func (privVal *PrivValidatorFS) String() string { return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep) } -// LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath -// or else generates a new one and saves it to the filePath. -func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS { - var PrivValidatorFS *PrivValidatorFS - if _, err := os.Stat(filePath); err == nil { - PrivValidatorFS = LoadPrivValidatorFS(filePath) - } else { - PrivValidatorFS = GenPrivValidatorFS(filePath) - PrivValidatorFS.Save() - } - return PrivValidatorFS -} - -// LoadPrivValidatorFS loads a PrivValidatorFS from the filePath. -func LoadPrivValidatorFS(filePath string) *PrivValidatorFS { - privValJSONBytes, err := ioutil.ReadFile(filePath) - if err != nil { - cmn.Exit(err.Error()) - } - privVal := PrivValidatorFS{} - err = json.Unmarshal(privValJSONBytes, &privVal) - if err != nil { - cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) - } - - privVal.filePath = filePath - privVal.Signer = NewDefaultSigner(privVal.PrivKey) - return &privVal -} - -// GenPrivValidatorFS generates a new validator with randomly generated private key -// and sets the filePath, but does not call Save(). -func GenPrivValidatorFS(filePath string) *PrivValidatorFS { - privKey := crypto.GenPrivKeyEd25519().Wrap() - return &PrivValidatorFS{ - Address: privKey.PubKey().Address(), - PubKey: privKey.PubKey(), - PrivKey: privKey, - LastStep: stepNone, - Signer: NewDefaultSigner(privKey), - filePath: filePath, - } -} - -// LoadPrivValidatorWithSigner loads a PrivValidatorFS with a custom -// signer object. The PrivValidatorFS handles double signing prevention by persisting -// data to the filePath, while the Signer handles the signing. -// If the filePath does not exist, the PrivValidatorFS must be created manually and saved. -func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(crypto.PubKey) Signer) *PrivValidatorFS { - privValJSONBytes, err := ioutil.ReadFile(filePath) - if err != nil { - cmn.Exit(err.Error()) - } - privVal := PrivValidatorFS{} - err = json.Unmarshal(privValJSONBytes, &privVal) - if err != nil { - cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) - } - - privVal.filePath = filePath - privVal.Signer = signerFunc(privVal.PubKey) - return &privVal -} - -//------------------------------------- - -//------------------------------------- - -// Signer is an interface that defines how to sign messages. -// It is the caller's duty to verify the msg before calling Sign, -// eg. to avoid double signing. -// Currently, the only callers are SignVote, SignProposal, and SignHeartbeat. -type Signer interface { - Sign(msg []byte) (crypto.Signature, error) -} - -// DefaultSigner implements Signer. -// It uses a standard, unencrypted crypto.PrivKey. -type DefaultSigner struct { - PrivKey crypto.PrivKey `json:"priv_key"` -} - -// NewDefaultSigner returns an instance of DefaultSigner. -func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner { - return &DefaultSigner{ - PrivKey: priv, - } -} - -// Sign implements Signer. It signs the byte slice with a private key. -func (ds *DefaultSigner) Sign(msg []byte) (crypto.Signature, error) { - return ds.PrivKey.Sign(msg), nil -} - //------------------------------------- type PrivValidatorsByAddress []*PrivValidatorFS