github.com/ethersphere/bee/v2@v2.2.0/pkg/feeds/feed.go (about) 1 // Copyright 2021 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package feeds implements generic interfaces and methods for time-based feeds 6 // indexing schemes are implemented in subpackages 7 // - epochs 8 // - sequence 9 package feeds 10 11 import ( 12 "encoding" 13 "errors" 14 "fmt" 15 "strings" 16 17 "github.com/ethereum/go-ethereum/common" 18 "github.com/ethersphere/bee/v2/pkg/crypto" 19 "github.com/ethersphere/bee/v2/pkg/soc" 20 "github.com/ethersphere/bee/v2/pkg/storage" 21 "github.com/ethersphere/bee/v2/pkg/swarm" 22 ) 23 24 var ErrFeedTypeNotFound = errors.New("no such feed type") 25 26 // Factory creates feed lookups for different types of feeds. 27 type Factory interface { 28 NewLookup(Type, *Feed) (Lookup, error) 29 } 30 31 // Type enumerates the time-based feed types 32 type Type int 33 34 const ( 35 Sequence Type = iota 36 Epoch 37 ) 38 39 func (t Type) String() string { 40 switch t { 41 case Sequence: 42 return "Sequence" 43 case Epoch: 44 return "Epoch" 45 default: 46 return "" 47 } 48 } 49 50 // FromString constructs the type from a string 51 func (t *Type) FromString(s string) error { 52 switch s = strings.ToLower(s); s { 53 case "sequence": 54 *t = Sequence 55 case "epoch": 56 *t = Epoch 57 default: 58 return ErrFeedTypeNotFound 59 } 60 return nil 61 } 62 63 type id struct { 64 topic []byte 65 index []byte 66 } 67 68 var _ encoding.BinaryMarshaler = (*id)(nil) 69 70 func (i *id) MarshalBinary() ([]byte, error) { 71 return crypto.LegacyKeccak256(append(append([]byte{}, i.topic...), i.index...)) 72 } 73 74 // Feed is representing an epoch based feed 75 type Feed struct { 76 Topic []byte 77 Owner common.Address 78 } 79 80 // New constructs an epoch based feed from a keccak256 digest of a plaintext 81 // topic and an ether address. 82 func New(topic []byte, owner common.Address) *Feed { 83 return &Feed{topic, owner} 84 } 85 86 // Index is the interface for feed implementations. 87 type Index interface { 88 encoding.BinaryMarshaler 89 Next(last int64, at uint64) Index 90 fmt.Stringer 91 } 92 93 // Update represents an update instance of a feed, i.e., pairing of a Feed with an Epoch 94 type Update struct { 95 *Feed 96 index Index 97 } 98 99 // Update called on a feed with an index and returns an Update 100 func (f *Feed) Update(index Index) *Update { 101 return &Update{f, index} 102 } 103 104 // NewUpdate creates an update from an index, timestamp, payload and signature 105 func NewUpdate(f *Feed, idx Index, timestamp int64, payload, sig []byte) (swarm.Chunk, error) { 106 id, err := f.Update(idx).Id() 107 if err != nil { 108 return nil, fmt.Errorf("update: %w", err) 109 } 110 cac, err := toChunk(uint64(timestamp), payload) 111 if err != nil { 112 return nil, fmt.Errorf("toChunk: %w", err) 113 } 114 115 ss, err := soc.NewSigned(id, cac, f.Owner.Bytes(), sig) 116 if err != nil { 117 return nil, fmt.Errorf("new signed soc: %w", err) 118 } 119 120 ch, err := ss.Chunk() 121 if err != nil { 122 return nil, fmt.Errorf("new chunk: %w", err) 123 } 124 125 if !soc.Valid(ch) { 126 return nil, storage.ErrInvalidChunk 127 } 128 return ch, nil 129 } 130 131 // Id calculates the identifier if a feed update to be used in single owner chunks 132 func (u *Update) Id() ([]byte, error) { 133 return Id(u.Topic, u.index) 134 } 135 136 // Id calculates the feed id from a topic and an index 137 func Id(topic []byte, index Index) ([]byte, error) { 138 indexBytes, err := index.MarshalBinary() 139 if err != nil { 140 return nil, err 141 } 142 i := &id{topic, indexBytes} 143 return i.MarshalBinary() 144 } 145 146 // Address calculates the soc address of a feed update 147 func (u *Update) Address() (swarm.Address, error) { 148 var addr swarm.Address 149 i, err := u.Id() 150 if err != nil { 151 return addr, err 152 } 153 return soc.CreateAddress(i, u.Owner[:]) 154 }