105 lines
3.6 KiB
Go
105 lines
3.6 KiB
Go
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) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
|
return r.getChainRandomness(ctx, pers, round, entropy, false)
|
|
}
|
|
|
|
func (r *ReplayingRand) GetChainRandomnessLookingBack(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.GetChainRandomnessLookingBack(ctx, pers, round, entropy)
|
|
}
|
|
|
|
return r.fallback.GetChainRandomnessLookingForward(ctx, pers, round, entropy)
|
|
}
|
|
|
|
func (r *ReplayingRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
|
return r.getBeaconRandomness(ctx, pers, round, entropy, false)
|
|
}
|
|
|
|
func (r *ReplayingRand) GetBeaconRandomnessLookingBack(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.GetBeaconRandomnessLookingBack(ctx, pers, round, entropy)
|
|
}
|
|
|
|
return r.fallback.GetBeaconRandomnessLookingForward(ctx, pers, round, entropy)
|
|
}
|