Browse Source

lite2: cross-check new header with all witnesses (#4373)

As opposed to checking a random witness, all witnesses provided should be used as a reference against the header provided by the primary node. This increases security (at the tradeoff of speed) but also gives control to the user. The more witnesses provided, the more secure the lite client can be.
pull/4372/head
Callum Waters 4 years ago
committed by GitHub
parent
commit
af37db39b0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 20 deletions
  1. +20
    -20
      lite2/client.go

+ 20
- 20
lite2/client.go View File

@ -11,7 +11,6 @@ import (
"github.com/tendermint/tendermint/libs/log"
tmmath "github.com/tendermint/tendermint/libs/math"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/lite2/provider"
"github.com/tendermint/tendermint/lite2/store"
"github.com/tendermint/tendermint/types"
@ -558,7 +557,7 @@ func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.Vali
return errors.Errorf("header at more recent height #%d exists", c.trustedHeader.Height)
}
if err := c.compareNewHeaderWithRandomWitness(newHeader); err != nil {
if err := c.compareNewHeaderWithWitnesses(newHeader); err != nil {
c.logger.Error("Error when comparing new header with one from a witness", "err", err)
return err
}
@ -855,32 +854,33 @@ func (c *Client) backwards(toHeight int64, fromHeader *types.SignedHeader, now t
return trustedHeader, nil
}
// compare header with one from a random witness.
func (c *Client) compareNewHeaderWithRandomWitness(h *types.SignedHeader) error {
// compare header with all witnesses provided.
func (c *Client) compareNewHeaderWithWitnesses(h *types.SignedHeader) error {
c.providerMutex.Lock()
defer c.providerMutex.Unlock()
// 0. Check witnesses exist
if len(c.witnesses) == 0 {
return errors.New("could not find any witnesses")
}
// 1. Pick a witness.
witness := c.witnesses[tmrand.Intn(len(c.witnesses))]
c.providerMutex.Unlock()
// 1. Loop through all witnesses.
for _, witness := range c.witnesses {
// 2. Fetch the header.
altH, err := witness.SignedHeader(h.Height)
if err != nil {
return errors.Wrapf(err,
"failed to obtain header #%d from the witness %v", h.Height, witness)
}
// 2. Fetch the header.
altH, err := witness.SignedHeader(h.Height)
if err != nil {
return errors.Wrapf(err,
"failed to obtain header #%d from the witness %v", h.Height, witness)
}
// 3. Compare hashes.
if !bytes.Equal(h.Hash(), altH.Hash()) {
// TODO: One of the providers is lying. Send the evidence to fork
// accountability server.
return errors.Errorf(
"header hash %X does not match one %X from the witness %v",
h.Hash(), altH.Hash(), witness)
// 3. Compare hashes.
if !bytes.Equal(h.Hash(), altH.Hash()) {
// TODO: One of the providers is lying. Send the evidence to fork
// accountability server.
return errors.Errorf(
"header hash %X does not match one %X from the witness %v",
h.Hash(), altH.Hash(), witness)
}
}
return nil


Loading…
Cancel
Save