mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-07 13:55:17 +00:00
@@ -84,11 +84,12 @@ func SkippingVerification(trustLevel tmmath.Fraction) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// AlternativeSources option can be used to supply alternative providers, which
|
||||
// will be used for cross-checking the primary provider.
|
||||
func AlternativeSources(providers []provider.Provider) Option {
|
||||
// Witnesses option can be used to supply providers, which will be used for
|
||||
// cross-checking the primary provider. A witness can become a primary iff the
|
||||
// current primary is unavailable.
|
||||
func Witnesses(providers []provider.Provider) Option {
|
||||
return func(c *Client) {
|
||||
c.alternatives = providers
|
||||
c.witnesses = providers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +143,8 @@ type Client struct {
|
||||
// Primary provider of new headers.
|
||||
primary provider.Provider
|
||||
|
||||
// Alternative providers for checking the primary for misbehavior by
|
||||
// comparing data.
|
||||
alternatives []provider.Provider
|
||||
// See Witnesses option
|
||||
witnesses []provider.Provider
|
||||
|
||||
// Where trusted headers are stored.
|
||||
trustedStore store.Store
|
||||
@@ -153,13 +153,15 @@ type Client struct {
|
||||
// Highest next validator set from the store (height=H+1).
|
||||
trustedNextVals *types.ValidatorSet
|
||||
|
||||
updatePeriod time.Duration
|
||||
// See UpdatePeriod option
|
||||
updatePeriod time.Duration
|
||||
// See RemoveNoLongerTrustedHeadersPeriod option
|
||||
removeNoLongerTrustedHeadersPeriod time.Duration
|
||||
routinesWaitGroup sync.WaitGroup
|
||||
|
||||
// See ConfirmationFunction option
|
||||
confirmationFn func(action string) bool
|
||||
|
||||
quit chan struct{}
|
||||
routinesWaitGroup sync.WaitGroup
|
||||
quit chan struct{}
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
@@ -518,8 +520,9 @@ func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
|
||||
return errors.Errorf("header at more recent height #%d exists", c.trustedHeader.Height)
|
||||
}
|
||||
|
||||
if len(c.alternatives) > 0 {
|
||||
if err := c.compareNewHeaderWithRandomAlternative(newHeader); err != nil {
|
||||
if len(c.witnesses) > 0 {
|
||||
if err := c.compareNewHeaderWithRandomWitness(newHeader); err != nil {
|
||||
c.logger.Error("Error when comparing new header with one from a witness", "err", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -721,25 +724,25 @@ func (c *Client) fetchHeaderAndValsAtHeight(height int64) (*types.SignedHeader,
|
||||
return h, vals, nil
|
||||
}
|
||||
|
||||
// compare header with one from a random alternative provider.
|
||||
func (c *Client) compareNewHeaderWithRandomAlternative(h *types.SignedHeader) error {
|
||||
// 1. Pick an alternative provider.
|
||||
p := c.alternatives[tmrand.Intn(len(c.alternatives))]
|
||||
// compare header with one from a random witness.
|
||||
func (c *Client) compareNewHeaderWithRandomWitness(h *types.SignedHeader) error {
|
||||
// 1. Pick a witness.
|
||||
witness := c.witnesses[tmrand.Intn(len(c.witnesses))]
|
||||
|
||||
// 2. Fetch the header.
|
||||
altHeader, err := p.SignedHeader(h.Height)
|
||||
altH, err := witness.SignedHeader(h.Height)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err,
|
||||
"failed to obtain header #%d from alternative provider %v", h.Height, p)
|
||||
"failed to obtain header #%d from the witness %v", h.Height, witness)
|
||||
}
|
||||
|
||||
// 3. Compare hashes.
|
||||
if !bytes.Equal(h.Hash(), altHeader.Hash()) {
|
||||
if !bytes.Equal(h.Hash(), altH.Hash()) {
|
||||
// TODO: One of the providers is lying. Send the evidence to fork
|
||||
// accountability server.
|
||||
return errors.Errorf(
|
||||
"new header hash %X does not match one from alternative provider %X",
|
||||
h.Hash(), altHeader.Hash())
|
||||
"header hash %X does not match one %X from the witness %v",
|
||||
h.Hash(), altH.Hash(), witness)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user