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