github.com/vipernet-xyz/tm@v0.34.24/light/provider/mock/mock.go (about) 1 package mock 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 "sync" 9 "time" 10 11 "github.com/vipernet-xyz/tm/light/provider" 12 "github.com/vipernet-xyz/tm/types" 13 ) 14 15 type Mock struct { 16 chainID string 17 18 mtx sync.Mutex 19 headers map[int64]*types.SignedHeader 20 vals map[int64]*types.ValidatorSet 21 evidenceToReport map[string]types.Evidence // hash => evidence 22 latestHeight int64 23 } 24 25 var _ provider.Provider = (*Mock)(nil) 26 27 // New creates a mock provider with the given set of headers and validator 28 // sets. 29 func New(chainID string, headers map[int64]*types.SignedHeader, vals map[int64]*types.ValidatorSet) *Mock { 30 height := int64(0) 31 for h := range headers { 32 if h > height { 33 height = h 34 } 35 } 36 return &Mock{ 37 chainID: chainID, 38 headers: headers, 39 vals: vals, 40 evidenceToReport: make(map[string]types.Evidence), 41 latestHeight: height, 42 } 43 } 44 45 // ChainID returns the blockchain ID. 46 func (p *Mock) ChainID() string { 47 return p.chainID 48 } 49 50 func (p *Mock) String() string { 51 var headers strings.Builder 52 for _, h := range p.headers { 53 fmt.Fprintf(&headers, " %d:%X", h.Height, h.Hash()) 54 } 55 56 var vals strings.Builder 57 for _, v := range p.vals { 58 fmt.Fprintf(&vals, " %X", v.Hash()) 59 } 60 61 return fmt.Sprintf("Mock{headers: %s, vals: %v}", headers.String(), vals.String()) 62 } 63 64 func (p *Mock) LightBlock(ctx context.Context, height int64) (*types.LightBlock, error) { 65 p.mtx.Lock() 66 defer p.mtx.Unlock() 67 68 // allocate a window of time for contexts to be canceled 69 select { 70 case <-ctx.Done(): 71 return nil, ctx.Err() 72 case <-time.After(10 * time.Millisecond): 73 } 74 75 var lb *types.LightBlock 76 77 if height > p.latestHeight { 78 return nil, provider.ErrHeightTooHigh 79 } 80 81 if height == 0 && len(p.headers) > 0 { 82 height = p.latestHeight 83 } 84 85 if _, ok := p.headers[height]; ok { 86 sh := p.headers[height] 87 vals := p.vals[height] 88 lb = &types.LightBlock{ 89 SignedHeader: sh, 90 ValidatorSet: vals, 91 } 92 } 93 if lb == nil { 94 return nil, provider.ErrLightBlockNotFound 95 } 96 if lb.SignedHeader == nil || lb.ValidatorSet == nil { 97 return nil, provider.ErrBadLightBlock{Reason: errors.New("nil header or vals")} 98 } 99 if err := lb.ValidateBasic(lb.ChainID); err != nil { 100 return nil, provider.ErrBadLightBlock{Reason: err} 101 } 102 return lb, nil 103 } 104 105 func (p *Mock) ReportEvidence(_ context.Context, ev types.Evidence) error { 106 p.evidenceToReport[string(ev.Hash())] = ev 107 return nil 108 } 109 110 func (p *Mock) HasEvidence(ev types.Evidence) bool { 111 _, ok := p.evidenceToReport[string(ev.Hash())] 112 return ok 113 } 114 115 func (p *Mock) AddLightBlock(lb *types.LightBlock) { 116 p.mtx.Lock() 117 defer p.mtx.Unlock() 118 119 if err := lb.ValidateBasic(lb.ChainID); err != nil { 120 panic(fmt.Sprintf("unable to add light block, err: %v", err)) 121 } 122 p.headers[lb.Height] = lb.SignedHeader 123 p.vals[lb.Height] = lb.ValidatorSet 124 if lb.Height > p.latestHeight { 125 p.latestHeight = lb.Height 126 } 127 } 128 129 func (p *Mock) Copy(id string) *Mock { 130 return New(id, p.headers, p.vals) 131 }