-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
rand_replay.go
108 lines (85 loc) · 3.78 KB
/
rand_replay.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
package conformance
import (
"bytes"
"context"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/test-vectors/schema"
"github.com/filecoin-project/lotus/chain/vm"
)
type ReplayingRand struct {
reporter Reporter
recorded schema.Randomness
fallback vm.Rand
}
var _ vm.Rand = (*ReplayingRand)(nil)
// NewReplayingRand replays recorded randomness when requested, falling back to
// fixed randomness if the value cannot be found; hence this is a safe
// backwards-compatible replacement for fixedRand.
func NewReplayingRand(reporter Reporter, recorded schema.Randomness) *ReplayingRand {
return &ReplayingRand{
reporter: reporter,
recorded: recorded,
fallback: NewFixedRand(),
}
}
func (r *ReplayingRand) match(requested schema.RandomnessRule) ([]byte, bool) {
for _, other := range r.recorded {
if other.On.Kind == requested.Kind &&
other.On.Epoch == requested.Epoch &&
other.On.DomainSeparationTag == requested.DomainSeparationTag &&
bytes.Equal(other.On.Entropy, requested.Entropy) {
return other.Return, true
}
}
return nil, false
}
func (r *ReplayingRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return r.getChainRandomness(ctx, pers, round, entropy, false)
}
func (r *ReplayingRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return r.getChainRandomness(ctx, pers, round, entropy, true)
}
func (r *ReplayingRand) getChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
rule := schema.RandomnessRule{
Kind: schema.RandomnessChain,
DomainSeparationTag: int64(pers),
Epoch: int64(round),
Entropy: entropy,
}
if ret, ok := r.match(rule); ok {
r.reporter.Logf("returning saved chain randomness: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
return ret, nil
}
r.reporter.Logf("returning fallback chain randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy)
if lookback {
return r.fallback.GetChainRandomnessV1(ctx, pers, round, entropy)
}
return r.fallback.GetChainRandomnessV2(ctx, pers, round, entropy)
}
func (r *ReplayingRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return r.getBeaconRandomness(ctx, pers, round, entropy, false)
}
func (r *ReplayingRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return r.getBeaconRandomness(ctx, pers, round, entropy, true)
}
func (r *ReplayingRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return r.getBeaconRandomness(ctx, pers, round, entropy, true)
}
func (r *ReplayingRand) getBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
rule := schema.RandomnessRule{
Kind: schema.RandomnessBeacon,
DomainSeparationTag: int64(pers),
Epoch: int64(round),
Entropy: entropy,
}
if ret, ok := r.match(rule); ok {
r.reporter.Logf("returning saved beacon randomness: dst=%d, epoch=%d, entropy=%x, result=%x", pers, round, entropy, ret)
return ret, nil
}
r.reporter.Logf("returning fallback beacon randomness: dst=%d, epoch=%d, entropy=%x", pers, round, entropy)
if lookback {
return r.fallback.GetBeaconRandomnessV1(ctx, pers, round, entropy)
}
return r.fallback.GetBeaconRandomnessV3(ctx, pers, round, entropy)
}