2017-07-13 10:22:05 -07:00
|
|
|
package ibc
|
|
|
|
|
|
|
|
import (
|
2017-07-13 13:11:15 -07:00
|
|
|
wire "github.com/tendermint/go-wire"
|
2017-07-13 10:22:05 -07:00
|
|
|
"github.com/tendermint/light-client/certifiers"
|
|
|
|
|
|
|
|
"github.com/tendermint/basecoin/stack"
|
|
|
|
"github.com/tendermint/basecoin/state"
|
|
|
|
)
|
|
|
|
|
2017-07-13 13:11:15 -07:00
|
|
|
const (
|
|
|
|
prefixHash = "v"
|
|
|
|
prefixHeight = "h"
|
|
|
|
prefixPacket = "p"
|
|
|
|
)
|
|
|
|
|
2017-07-14 07:29:29 -07:00
|
|
|
// newCertifier loads up the current state of this chain to make a proper certifier
|
|
|
|
// it will load the most recent height before block h if h is positive
|
|
|
|
// if h < 0, it will load the latest height
|
2017-07-21 10:53:52 -07:00
|
|
|
func newCertifier(store state.SimpleDB, chainID string, h int) (*certifiers.InquiringCertifier, error) {
|
2017-07-13 10:22:05 -07:00
|
|
|
// each chain has their own prefixed subspace
|
2017-07-14 07:29:29 -07:00
|
|
|
p := newDBProvider(store)
|
2017-07-13 10:22:05 -07:00
|
|
|
|
2017-07-14 07:29:29 -07:00
|
|
|
var seed certifiers.Seed
|
|
|
|
var err error
|
|
|
|
if h > 0 {
|
|
|
|
// this gets the most recent verified seed below the specified height
|
|
|
|
seed, err = p.GetByHeight(h)
|
|
|
|
} else {
|
|
|
|
// 0 or negative means start at latest seed
|
|
|
|
seed, err = certifiers.LatestSeed(p)
|
|
|
|
}
|
2017-07-13 10:22:05 -07:00
|
|
|
if err != nil {
|
2017-07-18 07:38:31 -07:00
|
|
|
return nil, ErrHeaderNotFound(h)
|
2017-07-13 10:22:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// we have no source for untrusted keys, but use the db to load trusted history
|
|
|
|
cert := certifiers.NewInquiring(chainID, seed.Validators, p,
|
|
|
|
certifiers.MissingProvider{})
|
|
|
|
return cert, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// dbProvider wraps our kv store so it integrates with light-client verification
|
|
|
|
type dbProvider struct {
|
2017-07-21 10:53:52 -07:00
|
|
|
byHash state.SimpleDB
|
2017-07-13 13:11:15 -07:00
|
|
|
byHeight *state.Span
|
|
|
|
}
|
|
|
|
|
2017-07-21 10:53:52 -07:00
|
|
|
func newDBProvider(store state.SimpleDB) *dbProvider {
|
2017-07-13 13:11:15 -07:00
|
|
|
return &dbProvider{
|
|
|
|
byHash: stack.PrefixedStore(prefixHash, store),
|
|
|
|
byHeight: state.NewSpan(stack.PrefixedStore(prefixHeight, store)),
|
|
|
|
}
|
2017-07-13 10:22:05 -07:00
|
|
|
}
|
|
|
|
|
2017-07-13 13:11:15 -07:00
|
|
|
var _ certifiers.Provider = &dbProvider{}
|
2017-07-13 10:22:05 -07:00
|
|
|
|
2017-07-13 13:11:15 -07:00
|
|
|
func (d *dbProvider) StoreSeed(seed certifiers.Seed) error {
|
|
|
|
// TODO: don't duplicate data....
|
|
|
|
b := wire.BinaryBytes(seed)
|
|
|
|
d.byHash.Set(seed.Hash(), b)
|
|
|
|
d.byHeight.Set(uint64(seed.Height()), b)
|
2017-07-13 10:22:05 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-07-13 13:11:15 -07:00
|
|
|
func (d *dbProvider) GetByHeight(h int) (seed certifiers.Seed, err error) {
|
|
|
|
b, _ := d.byHeight.LTE(uint64(h))
|
|
|
|
if b == nil {
|
|
|
|
return seed, certifiers.ErrSeedNotFound()
|
|
|
|
}
|
|
|
|
err = wire.ReadBinaryBytes(b, &seed)
|
|
|
|
return
|
2017-07-13 10:22:05 -07:00
|
|
|
}
|
2017-07-13 13:11:15 -07:00
|
|
|
|
|
|
|
func (d *dbProvider) GetByHash(hash []byte) (seed certifiers.Seed, err error) {
|
|
|
|
b := d.byHash.Get(hash)
|
|
|
|
if b == nil {
|
|
|
|
return seed, certifiers.ErrSeedNotFound()
|
|
|
|
}
|
|
|
|
err = wire.ReadBinaryBytes(b, &seed)
|
|
|
|
return
|
2017-07-13 10:22:05 -07:00
|
|
|
}
|
2017-07-18 05:27:53 -07:00
|
|
|
|
|
|
|
// GetExactHeight is like GetByHeight, but returns an error instead of
|
|
|
|
// closest match if there is no exact match
|
|
|
|
func (d *dbProvider) GetExactHeight(h int) (seed certifiers.Seed, err error) {
|
|
|
|
seed, err = d.GetByHeight(h)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if seed.Height() != h {
|
|
|
|
err = ErrHeaderNotFound(h)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|