-
Notifications
You must be signed in to change notification settings - Fork 968
/
verify.go
156 lines (145 loc) · 4.76 KB
/
verify.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
155
156
package backfill
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/network/forks"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
var errInvalidBatchChain = errors.New("parent_root of block does not match the previous block's root")
var errProposerIndexTooHigh = errors.New("proposer index not present in origin state")
var errUnknownDomain = errors.New("runtime error looking up signing domain for fork")
// verifiedROBlocks represents a slice of blocks that have passed signature verification.
type verifiedROBlocks []blocks.ROBlock
func (v verifiedROBlocks) blobIdents(retentionStart primitives.Slot) ([]blobSummary, error) {
// early return if the newest block is outside the retention window
if len(v) > 0 && v[len(v)-1].Block().Slot() < retentionStart {
return nil, nil
}
bs := make([]blobSummary, 0)
for i := range v {
if v[i].Block().Slot() < retentionStart {
continue
}
if v[i].Block().Version() < version.Deneb {
continue
}
c, err := v[i].Block().Body().BlobKzgCommitments()
if err != nil {
return nil, errors.Wrapf(err, "unexpected error checking commitments for block root %#x", v[i].Root())
}
if len(c) == 0 {
continue
}
for ci := range c {
bs = append(bs, blobSummary{
blockRoot: v[i].Root(), signature: v[i].Signature(),
index: uint64(ci), commitment: bytesutil.ToBytes48(c[ci])})
}
}
return bs, nil
}
type verifier struct {
keys [][fieldparams.BLSPubkeyLength]byte
maxVal primitives.ValidatorIndex
domain *domainCache
}
// TODO: rewrite this to use ROBlock.
func (vr verifier) verify(blks []interfaces.ReadOnlySignedBeaconBlock) (verifiedROBlocks, error) {
var err error
result := make([]blocks.ROBlock, len(blks))
sigSet := bls.NewSet()
for i := range blks {
result[i], err = blocks.NewROBlock(blks[i])
if err != nil {
return nil, err
}
if i > 0 && result[i-1].Root() != result[i].Block().ParentRoot() {
p, b := result[i-1], result[i]
return nil, errors.Wrapf(errInvalidBatchChain,
"slot %d parent_root=%#x, slot %d root=%#x",
b.Block().Slot(), b.Block().ParentRoot(),
p.Block().Slot(), p.Root())
}
set, err := vr.blockSignatureBatch(result[i])
if err != nil {
return nil, err
}
sigSet.Join(set)
}
v, err := sigSet.Verify()
if err != nil {
return nil, errors.Wrap(err, "block signature verification error")
}
if !v {
return nil, errors.New("batch block signature verification failed")
}
return result, nil
}
func (vr verifier) blockSignatureBatch(b blocks.ROBlock) (*bls.SignatureBatch, error) {
pidx := b.Block().ProposerIndex()
if pidx > vr.maxVal {
return nil, errProposerIndexTooHigh
}
dom, err := vr.domain.forEpoch(slots.ToEpoch(b.Block().Slot()))
if err != nil {
return nil, err
}
sig := b.Signature()
pk := vr.keys[pidx][:]
root := b.Root()
rootF := func() ([32]byte, error) { return root, nil }
return signing.BlockSignatureBatch(pk, sig[:], dom, rootF)
}
func newBackfillVerifier(vr []byte, keys [][fieldparams.BLSPubkeyLength]byte) (*verifier, error) {
dc, err := newDomainCache(vr, params.BeaconConfig().DomainBeaconProposer,
forks.NewOrderedSchedule(params.BeaconConfig()))
if err != nil {
return nil, err
}
v := &verifier{
keys: keys,
domain: dc,
}
v.maxVal = primitives.ValidatorIndex(len(v.keys) - 1)
return v, nil
}
// domainCache provides a fast signing domain lookup by epoch.
type domainCache struct {
fsched forks.OrderedSchedule
forkDomains map[[4]byte][]byte
dType [bls.DomainByteLength]byte
}
func newDomainCache(vRoot []byte, dType [bls.DomainByteLength]byte, fsched forks.OrderedSchedule) (*domainCache, error) {
dc := &domainCache{
fsched: fsched,
forkDomains: make(map[[4]byte][]byte),
dType: dType,
}
for _, entry := range fsched {
d, err := signing.ComputeDomain(dc.dType, entry.Version[:], vRoot)
if err != nil {
return nil, errors.Wrapf(err, "failed to pre-compute signing domain for fork version=%#x", entry.Version)
}
dc.forkDomains[entry.Version] = d
}
return dc, nil
}
func (dc *domainCache) forEpoch(e primitives.Epoch) ([]byte, error) {
fork, err := dc.fsched.VersionForEpoch(e)
if err != nil {
return nil, err
}
d, ok := dc.forkDomains[fork]
if !ok {
return nil, errors.Wrapf(errUnknownDomain, "fork version=%#x, epoch=%d", fork, e)
}
return d, nil
}