Fix Drand fetching around null tipsets
This commit is contained in:
parent
d9e711eac5
commit
c3c46e9097
@ -54,7 +54,8 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry)
|
||||
}
|
||||
|
||||
func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 {
|
||||
return uint64(epoch)
|
||||
// offset for better testing
|
||||
return uint64(epoch + 100)
|
||||
}
|
||||
|
||||
var _ RandomBeacon = (*mockBeacon)(nil)
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
@ -280,7 +282,7 @@ func (t *TipSetExecutor) ExecuteTipSet(ctx context.Context, sm *stmgr.StateManag
|
||||
parentEpoch = parent.Height
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.ChainStore(), ts.Cids())
|
||||
r := rand.NewStateRand(sm.ChainStore(), ts.Cids(), sm.Beacon())
|
||||
|
||||
blkmsgs, err := sm.ChainStore().BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@ -219,7 +221,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
|
||||
}
|
||||
|
||||
vrfBase, err := store.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes())
|
||||
vrfBase, err := rand.DrawRandomness(rBeacon.Data, crypto.DomainSeparationTag_ElectionProofProduction, h.Height, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not draw randomness: %w", err)
|
||||
}
|
||||
@ -283,7 +285,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
}
|
||||
|
||||
vrfBase, err := store.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes())
|
||||
vrfBase, err := rand.DrawRandomness(beaconBase.Data, crypto.DomainSeparationTag_TicketProduction, h.Height-build.TicketRandomnessLookback, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
|
||||
}
|
||||
@ -388,7 +390,7 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
|
||||
rbase = h.BeaconEntries[len(h.BeaconEntries)-1]
|
||||
}
|
||||
|
||||
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
|
||||
rand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -246,11 +248,6 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
||||
mgen[genesis2.MinerAddress(uint64(i))] = &wppProvider{}
|
||||
}
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
||||
}
|
||||
|
||||
miners := []address.Address{maddr1, maddr2}
|
||||
|
||||
beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}}
|
||||
@ -259,6 +256,11 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
//}
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us, beac)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
||||
}
|
||||
|
||||
gen := &ChainGen{
|
||||
bs: bs,
|
||||
cs: cs,
|
||||
@ -307,6 +309,10 @@ func (cg *ChainGen) ChainStore() *store.ChainStore {
|
||||
return cg.cs
|
||||
}
|
||||
|
||||
func (cg *ChainGen) BeaconSchedule() beacon.Schedule {
|
||||
return cg.beacon
|
||||
}
|
||||
|
||||
func (cg *ChainGen) Genesis() *types.BlockHeader {
|
||||
return cg.genesis
|
||||
}
|
||||
@ -365,7 +371,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
buf.Write(pts.MinTicket().VRFProof)
|
||||
}
|
||||
|
||||
ticketRand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes())
|
||||
ticketRand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@ -397,12 +403,15 @@ type MinedTipSet struct {
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
|
||||
mts, err := cg.NextTipSetFromMiners(cg.CurTipset.TipSet(), cg.Miners, 0)
|
||||
return cg.NextTipSetWithNulls(0)
|
||||
}
|
||||
|
||||
func (cg *ChainGen) NextTipSetWithNulls(nulls abi.ChainEpoch) (*MinedTipSet, error) {
|
||||
mts, err := cg.NextTipSetFromMiners(cg.CurTipset.TipSet(), cg.Miners, nulls)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cg.CurTipset = mts.TipSet
|
||||
return mts, nil
|
||||
}
|
||||
|
||||
@ -586,29 +595,11 @@ type mca struct {
|
||||
}
|
||||
|
||||
func (mca mca) StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
if mca.sm.GetNtwkVersion(ctx, randEpoch) >= network.Version13 {
|
||||
return mca.sm.ChainStore().GetChainRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return mca.sm.ChainStore().GetChainRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
return mca.sm.GetRandomnessFromTickets(ctx, personalization, randEpoch, entropy, tsk)
|
||||
}
|
||||
|
||||
func (mca mca) StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
if mca.sm.GetNtwkVersion(ctx, randEpoch) >= network.Version13 {
|
||||
return mca.sm.ChainStore().GetBeaconRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return mca.sm.ChainStore().GetBeaconRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
return mca.sm.GetRandomnessFromBeacon(ctx, personalization, randEpoch, entropy, tsk)
|
||||
}
|
||||
|
||||
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
||||
@ -644,7 +635,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
return nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
||||
}
|
||||
|
||||
electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes())
|
||||
electionRand, err := rand.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to draw randomness: %w", err)
|
||||
}
|
||||
|
@ -485,25 +485,31 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
|
||||
// TODO: copied from actors test harness, deduplicate or remove from here
|
||||
type fakeRand struct{}
|
||||
|
||||
func (fr *fakeRand) GetChainRandomnessLookingForward(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (fr *fakeRand) GetChainRandomnessV2(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (fr *fakeRand) GetChainRandomnessLookingBack(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (fr *fakeRand) GetChainRandomnessV1(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch * 1000))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (fr *fakeRand) GetBeaconRandomnessLookingForward(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (fr *fakeRand) GetBeaconRandomnessV3(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (fr *fakeRand) GetBeaconRandomnessLookingBack(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (fr *fakeRand) GetBeaconRandomnessV2(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (fr *fakeRand) GetBeaconRandomnessV1(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
out := make([]byte, 32)
|
||||
_, _ = rand.New(rand.NewSource(int64(randEpoch))).Read(out) //nolint
|
||||
return out, nil
|
||||
|
202
chain/rand/rand.go
Normal file
202
chain/rand/rand.go
Normal file
@ -0,0 +1,202 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
var log = logging.Logger("rand")
|
||||
|
||||
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
h := blake2b.New256()
|
||||
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
VRFDigest := blake2b.Sum256(rbase)
|
||||
_, err := h.Write(VRFDigest[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||
}
|
||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
_, err = h.Write(entropy)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing entropy: %w", err)
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (sr *stateRand) GetBeaconRandomnessTipset(ctx context.Context, round abi.ChainEpoch, lookback bool) (*types.TipSet, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetBeaconRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := sr.cs.LoadTipSet(types.NewTipSetKey(sr.blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := sr.cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return randTs, nil
|
||||
}
|
||||
|
||||
func (sr *stateRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetChainRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := sr.cs.LoadTipSet(types.NewTipSetKey(sr.blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := sr.cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := randTs.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
type stateRand struct {
|
||||
cs *store.ChainStore
|
||||
blks []cid.Cid
|
||||
beacon beacon.Schedule
|
||||
}
|
||||
|
||||
func NewStateRand(cs *store.ChainStore, blks []cid.Cid, b beacon.Schedule) vm.Rand {
|
||||
return &stateRand{
|
||||
cs: cs,
|
||||
blks: blks,
|
||||
beacon: b,
|
||||
}
|
||||
}
|
||||
|
||||
// network v0-12
|
||||
func (sr *stateRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return sr.GetChainRandomness(ctx, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
// network v13 and on
|
||||
func (sr *stateRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return sr.GetChainRandomness(ctx, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
// network v0-12
|
||||
func (sr *stateRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
randTs, err := sr.GetBeaconRandomnessTipset(ctx, round, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
be, err := sr.cs.GetLatestBeaconEntry(randTs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(be.Data, pers, round, entropy)
|
||||
}
|
||||
|
||||
// network v13
|
||||
func (sr *stateRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
randTs, err := sr.GetBeaconRandomnessTipset(ctx, round, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
be, err := sr.cs.GetLatestBeaconEntry(randTs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(be.Data, pers, round, entropy)
|
||||
}
|
||||
|
||||
// network v14 and on
|
||||
func (sr *stateRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, filecoinEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
if filecoinEpoch < 0 {
|
||||
return sr.GetBeaconRandomnessV2(ctx, pers, filecoinEpoch, entropy)
|
||||
}
|
||||
|
||||
be, err := sr.extractBeaconEntryForEpoch(ctx, filecoinEpoch)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get beacon entry as expected: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return DrawRandomness(be.Data, pers, filecoinEpoch, entropy)
|
||||
}
|
||||
|
||||
func (sr *stateRand) extractBeaconEntryForEpoch(ctx context.Context, filecoinEpoch abi.ChainEpoch) (*types.BeaconEntry, error) {
|
||||
randTs, err := sr.GetBeaconRandomnessTipset(ctx, filecoinEpoch, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
round := sr.beacon.BeaconForEpoch(filecoinEpoch).MaxBeaconRoundForEpoch(filecoinEpoch)
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := randTs.Blocks()[0].BeaconEntries
|
||||
for _, v := range cbe {
|
||||
if v.Round == round {
|
||||
return &v, nil
|
||||
}
|
||||
}
|
||||
|
||||
next, err := sr.cs.LoadTipSet(randTs.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load parents when searching back for beacon entry: %w", err)
|
||||
}
|
||||
|
||||
randTs = next
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("didn't find beacon for round %d (epoch %d)", round, filecoinEpoch)
|
||||
}
|
238
chain/rand/rand_test.go
Normal file
238
chain/rand/rand_test.go
Normal file
@ -0,0 +1,238 @@
|
||||
package rand_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
)
|
||||
|
||||
func init() {
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
// in v12 and before, if the tipset corresponding to round X is null, we fetch the latest beacon entry BEFORE X that's in a non-null ts
|
||||
func TestNullRandomnessV1(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cg, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
_, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height())
|
||||
beforeNullHeight := cg.CurTipset.TipSet().Height()
|
||||
|
||||
ts, err := cg.NextTipSetWithNulls(5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
entropy := []byte{0, 2, 3, 4}
|
||||
// arbitrarily chosen
|
||||
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
||||
|
||||
randEpoch := ts.TipSet.TipSet().Height() - 2
|
||||
|
||||
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(beforeNullHeight)+offset)
|
||||
|
||||
select {
|
||||
case resp := <-bch:
|
||||
if resp.Err != nil {
|
||||
t.Fatal(resp.Err)
|
||||
}
|
||||
|
||||
rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
require.Equal(t, rand1, abi.Randomness(rand2))
|
||||
|
||||
case <-ctx.Done():
|
||||
t.Fatal("timed out")
|
||||
}
|
||||
}
|
||||
|
||||
// at v13, if the tipset corresponding to round X is null, we fetch the latest beacon in the first non-null ts after X
|
||||
func TestNullRandomnessV2(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
sched := stmgr.UpgradeSchedule{
|
||||
{
|
||||
// prepare for upgrade.
|
||||
Network: network.Version9,
|
||||
Height: 1,
|
||||
Migration: filcns.UpgradeActorsV2,
|
||||
}, {
|
||||
Network: network.Version10,
|
||||
Height: 2,
|
||||
Migration: filcns.UpgradeActorsV3,
|
||||
}, {
|
||||
Network: network.Version12,
|
||||
Height: 3,
|
||||
Migration: filcns.UpgradeActorsV4,
|
||||
}, {
|
||||
Network: network.Version13,
|
||||
Height: 4,
|
||||
Migration: filcns.UpgradeActorsV5,
|
||||
},
|
||||
}
|
||||
|
||||
cg, err := gen.NewGeneratorWithUpgradeSchedule(sched)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
_, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height())
|
||||
|
||||
ts, err := cg.NextTipSetWithNulls(5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
entropy := []byte{0, 2, 3, 4}
|
||||
// arbitrarily chosen
|
||||
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
||||
|
||||
randEpoch := ts.TipSet.TipSet().Height() - 2
|
||||
|
||||
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(ts.TipSet.TipSet().Height())+offset)
|
||||
|
||||
select {
|
||||
case resp := <-bch:
|
||||
if resp.Err != nil {
|
||||
t.Fatal(resp.Err)
|
||||
}
|
||||
|
||||
// note that the randEpoch passed to DrawRandomness is still randEpoch (not the latest ts height)
|
||||
rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
require.Equal(t, rand1, abi.Randomness(rand2))
|
||||
|
||||
case <-ctx.Done():
|
||||
t.Fatal("timed out")
|
||||
}
|
||||
}
|
||||
|
||||
// after v14, if the tipset corresponding to round X is null, we still fetch the randomness for X (from the next non-null tipset)
|
||||
func TestNullRandomnessV3(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
sched := stmgr.UpgradeSchedule{
|
||||
{
|
||||
// prepare for upgrade.
|
||||
Network: network.Version9,
|
||||
Height: 1,
|
||||
Migration: filcns.UpgradeActorsV2,
|
||||
}, {
|
||||
Network: network.Version10,
|
||||
Height: 2,
|
||||
Migration: filcns.UpgradeActorsV3,
|
||||
}, {
|
||||
Network: network.Version12,
|
||||
Height: 3,
|
||||
Migration: filcns.UpgradeActorsV4,
|
||||
}, {
|
||||
Network: network.Version13,
|
||||
Height: 4,
|
||||
Migration: filcns.UpgradeActorsV5,
|
||||
}, {
|
||||
Network: network.Version14,
|
||||
Height: 5,
|
||||
Migration: filcns.UpgradeActorsV6,
|
||||
},
|
||||
}
|
||||
|
||||
cg, err := gen.NewGeneratorWithUpgradeSchedule(sched)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
_, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ts, err := cg.NextTipSetWithNulls(5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
offset := cg.CurTipset.Blocks[0].Header.BeaconEntries[len(cg.CurTipset.Blocks[0].Header.BeaconEntries)-1].Round - uint64(cg.CurTipset.TipSet().Height())
|
||||
|
||||
entropy := []byte{0, 2, 3, 4}
|
||||
// arbitrarily chosen
|
||||
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
||||
|
||||
randEpoch := ts.TipSet.TipSet().Height() - 2
|
||||
|
||||
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(randEpoch)+offset)
|
||||
|
||||
select {
|
||||
case resp := <-bch:
|
||||
if resp.Err != nil {
|
||||
t.Fatal(resp.Err)
|
||||
}
|
||||
|
||||
rand2, err := rand.DrawRandomness(resp.Entry.Data, pers, randEpoch, entropy)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
require.Equal(t, rand1, abi.Randomness(rand2))
|
||||
|
||||
case <-ctx.Done():
|
||||
t.Fatal("timed out")
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@ -21,7 +23,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
@ -351,7 +352,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
||||
return nil, xerrors.Errorf("failed to marshal miner address: %w", err)
|
||||
}
|
||||
|
||||
prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
prand, err := rand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
@ -14,7 +16,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
@ -74,7 +75,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: bstate,
|
||||
Epoch: pheight + 1,
|
||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||
Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon),
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Actors: sm.tsExec.NewActorRegistry(),
|
||||
Syscalls: sm.Syscalls,
|
||||
@ -185,7 +186,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon)
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
|
@ -158,7 +158,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
return st.Flush(ctx)
|
||||
}}})
|
||||
}}}, cg.BeaconSchedule())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -273,7 +273,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
|
||||
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
migrationCount++
|
||||
return root, nil
|
||||
}}})
|
||||
}}}, cg.BeaconSchedule())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -488,7 +488,7 @@ func TestForkPreMigration(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
}}},
|
||||
})
|
||||
}, cg.BeaconSchedule())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -4,6 +4,10 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@ -11,6 +15,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
// Used for genesis.
|
||||
@ -89,6 +94,7 @@ type StateManager struct {
|
||||
|
||||
tsExec Executor
|
||||
tsExecMonitor ExecMonitor
|
||||
beacon beacon.Schedule
|
||||
}
|
||||
|
||||
// Caches a single state tree
|
||||
@ -97,7 +103,7 @@ type treeCache struct {
|
||||
tree *state.StateTree
|
||||
}
|
||||
|
||||
func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule) (*StateManager, error) {
|
||||
func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, beacon beacon.Schedule) (*StateManager, error) {
|
||||
// If we have upgrades, make sure they're in-order and make sense.
|
||||
if err := us.Validate(); err != nil {
|
||||
return nil, err
|
||||
@ -143,6 +149,7 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder,
|
||||
cs: cs,
|
||||
tsExec: exec,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
beacon: beacon,
|
||||
tCache: treeCache{
|
||||
root: cid.Undef,
|
||||
tree: nil,
|
||||
@ -151,8 +158,8 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, em ExecMonitor) (*StateManager, error) {
|
||||
sm, err := NewStateManager(cs, exec, sys, us)
|
||||
func NewStateManagerWithUpgradeScheduleAndMonitor(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder, us UpgradeSchedule, b beacon.Schedule, em ExecMonitor) (*StateManager, error) {
|
||||
sm, err := NewStateManager(cs, exec, sys, us, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -199,6 +206,10 @@ func (sm *StateManager) ChainStore() *store.ChainStore {
|
||||
return sm.cs
|
||||
}
|
||||
|
||||
func (sm *StateManager) Beacon() beacon.Schedule {
|
||||
return sm.beacon
|
||||
}
|
||||
|
||||
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
|
||||
// Uses the `TipSet` `ts` to generate the VM state.
|
||||
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
@ -362,3 +373,38 @@ func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoc
|
||||
func (sm *StateManager) VMSys() vm.SyscallBuilder {
|
||||
return sm.Syscalls
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := sm.ChainStore().GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
|
||||
r := rand.NewStateRand(sm.ChainStore(), pts.Cids(), sm.beacon)
|
||||
rnv := sm.GetNtwkVersion(ctx, randEpoch)
|
||||
|
||||
if rnv >= network.Version14 {
|
||||
return r.GetBeaconRandomnessV3(ctx, personalization, randEpoch, entropy)
|
||||
} else if rnv == network.Version13 {
|
||||
return r.GetBeaconRandomnessV2(ctx, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return r.GetBeaconRandomnessV1(ctx, personalization, randEpoch, entropy)
|
||||
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
r := rand.NewStateRand(sm.ChainStore(), pts.Cids(), sm.beacon)
|
||||
rnv := sm.GetNtwkVersion(ctx, randEpoch)
|
||||
|
||||
if rnv >= network.Version13 {
|
||||
return r.GetChainRandomnessV2(ctx, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return r.GetChainRandomnessV1(ctx, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
@ -77,7 +79,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
// future. It's not guaranteed to be accurate... but that's fine.
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
r := rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon)
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: height,
|
||||
|
@ -1,182 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
h := blake2b.New256()
|
||||
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
VRFDigest := blake2b.Sum256(rbase)
|
||||
_, err := h.Write(VRFDigest[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||
}
|
||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
_, err = h.Write(entropy)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing entropy: %w", err)
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetBeaconRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
be, err := cs.GetLatestBeaconEntry(randTs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(be.Data, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetChainRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := randTs.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
cur := ts
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := cur.Blocks()[0].BeaconEntries
|
||||
if len(cbe) > 0 {
|
||||
return &cbe[len(cbe)-1], nil
|
||||
}
|
||||
|
||||
if cur.Height() == 0 {
|
||||
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
|
||||
}
|
||||
|
||||
next, err := cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
||||
return &types.BeaconEntry{
|
||||
Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
||||
type chainRand struct {
|
||||
cs *ChainStore
|
||||
blks []cid.Cid
|
||||
}
|
||||
|
||||
func NewChainRand(cs *ChainStore, blks []cid.Cid) vm.Rand {
|
||||
return &chainRand{
|
||||
cs: cs,
|
||||
blks: blks,
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
}
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
@ -1189,3 +1189,38 @@ func breakWeightTie(ts1, ts2 *types.TipSet) bool {
|
||||
log.Infof("weight tie left unbroken, default to %s", ts2.Key())
|
||||
return false
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
}
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
cur := ts
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := cur.Blocks()[0].BeaconEntries
|
||||
if len(cbe) > 0 {
|
||||
return &cbe[len(cbe)-1], nil
|
||||
}
|
||||
|
||||
if cur.Height() == 0 {
|
||||
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
|
||||
}
|
||||
|
||||
next, err := cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
||||
return &types.BeaconEntry{
|
||||
Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := cs.GetChainRandomnessLookingBack(context.TODO(), last.Cids(), crypto.DomainSeparationTag_SealRandomness, 500, nil)
|
||||
_, err := cg.StateManager().GetRandomnessFromTickets(context.TODO(), crypto.DomainSeparationTag_SealRandomness, 500, nil, last.Key())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -158,7 +158,7 @@ func TestChainExportImportFull(t *testing.T) {
|
||||
t.Fatal("imported chain differed from exported chain")
|
||||
}
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule())
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
|
||||
@ -1037,81 +1035,6 @@ func TestSyncCheckpointEarlierThanHead(t *testing.T) {
|
||||
require.True(tu.t, p1Head.Equals(b.TipSet()))
|
||||
}
|
||||
|
||||
func TestDrandNull(t *testing.T) {
|
||||
H := 10
|
||||
v5h := abi.ChainEpoch(50)
|
||||
ov5h := build.UpgradeHyperdriveHeight
|
||||
build.UpgradeHyperdriveHeight = v5h
|
||||
tu := prepSyncTestWithV5Height(t, H, v5h)
|
||||
|
||||
p0 := tu.addClientNode()
|
||||
p1 := tu.addClientNode()
|
||||
|
||||
tu.loadChainToNode(p0)
|
||||
tu.loadChainToNode(p1)
|
||||
|
||||
entropy := []byte{0, 2, 3, 4}
|
||||
// arbitrarily chosen
|
||||
pers := crypto.DomainSeparationTag_WinningPoStChallengeSeed
|
||||
|
||||
beforeNull := tu.g.CurTipset
|
||||
afterNull := tu.mineOnBlock(beforeNull, p0, nil, false, false, nil, 2, true)
|
||||
nullHeight := beforeNull.TipSet().Height() + 1
|
||||
if afterNull.TipSet().Height() == nullHeight {
|
||||
t.Fatal("didn't inject nulls as expected")
|
||||
}
|
||||
|
||||
rand, err := tu.nds[p0].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key())
|
||||
require.NoError(t, err)
|
||||
|
||||
// calculate the expected randomness based on the beacon BEFORE the null
|
||||
expectedBE := beforeNull.Blocks[0].Header.BeaconEntries
|
||||
expectedRand, err := store.DrawRandomness(expectedBE[len(expectedBE)-1].Data, pers, nullHeight, entropy)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, []byte(rand), expectedRand)
|
||||
|
||||
// zoom zoom to past the v5 upgrade by injecting many many nulls
|
||||
postUpgrade := tu.mineOnBlock(afterNull, p0, nil, false, false, nil, v5h, true)
|
||||
nv, err := tu.nds[p0].StateNetworkVersion(tu.ctx, postUpgrade.TipSet().Key())
|
||||
require.NoError(t, err)
|
||||
if nv <= network.Version13 {
|
||||
t.Fatal("expect to be v13 by now")
|
||||
}
|
||||
|
||||
afterNull = tu.mineOnBlock(postUpgrade, p0, nil, false, false, nil, 2, true)
|
||||
nullHeight = postUpgrade.TipSet().Height() + 1
|
||||
if afterNull.TipSet().Height() == nullHeight {
|
||||
t.Fatal("didn't inject nulls as expected")
|
||||
}
|
||||
|
||||
rand0, err := tu.nds[p0].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key())
|
||||
require.NoError(t, err)
|
||||
|
||||
// calculate the expected randomness based on the beacon AFTER the null
|
||||
expectedBE = afterNull.Blocks[0].Header.BeaconEntries
|
||||
expectedRand, err = store.DrawRandomness(expectedBE[len(expectedBE)-1].Data, pers, nullHeight, entropy)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, []byte(rand0), expectedRand)
|
||||
|
||||
// Introduce p1 to friendly p0 who has all the blocks
|
||||
require.NoError(t, tu.mn.LinkAll())
|
||||
tu.connect(p0, p1)
|
||||
tu.waitUntilNodeHasTs(p1, afterNull.TipSet().Key())
|
||||
p1Head := tu.getHead(p1)
|
||||
|
||||
// Yes, p1 syncs well to p0's chain
|
||||
require.Equal(tu.t, p1Head.Key(), afterNull.TipSet().Key())
|
||||
|
||||
// Yes, p1 sources the same randomness as p0
|
||||
rand1, err := tu.nds[p1].StateGetRandomnessFromBeacon(tu.ctx, pers, nullHeight, entropy, afterNull.TipSet().Key())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rand0, rand1)
|
||||
|
||||
build.UpgradeHyperdriveHeight = ov5h
|
||||
}
|
||||
|
||||
func TestInvalidHeight(t *testing.T) {
|
||||
H := 50
|
||||
tu := prepSyncTest(t, H)
|
||||
|
@ -219,9 +219,9 @@ func (rt *Runtime) GetRandomnessFromTickets(personalization crypto.DomainSeparat
|
||||
|
||||
rnv := rt.vm.ntwkVersion(rt.ctx, randEpoch)
|
||||
if rnv >= network.Version13 {
|
||||
res, err = rt.vm.rand.GetChainRandomnessLookingForward(rt.ctx, personalization, randEpoch, entropy)
|
||||
res, err = rt.vm.rand.GetChainRandomnessV2(rt.ctx, personalization, randEpoch, entropy)
|
||||
} else {
|
||||
res, err = rt.vm.rand.GetChainRandomnessLookingBack(rt.ctx, personalization, randEpoch, entropy)
|
||||
res, err = rt.vm.rand.GetChainRandomnessV1(rt.ctx, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -235,10 +235,12 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati
|
||||
var res []byte
|
||||
|
||||
rnv := rt.vm.ntwkVersion(rt.ctx, randEpoch)
|
||||
if rnv >= network.Version13 {
|
||||
res, err = rt.vm.rand.GetBeaconRandomnessLookingForward(rt.ctx, personalization, randEpoch, entropy)
|
||||
if rnv >= network.Version14 {
|
||||
res, err = rt.vm.rand.GetBeaconRandomnessV3(rt.ctx, personalization, randEpoch, entropy)
|
||||
} else if rnv == network.Version13 {
|
||||
res, err = rt.vm.rand.GetBeaconRandomnessV2(rt.ctx, personalization, randEpoch, entropy)
|
||||
} else {
|
||||
res, err = rt.vm.rand.GetBeaconRandomnessLookingBack(rt.ctx, personalization, randEpoch, entropy)
|
||||
res, err = rt.vm.rand.GetBeaconRandomnessV1(rt.ctx, personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -256,10 +256,11 @@ func NewVM(ctx context.Context, opts *VMOpts) (*VM, error) {
|
||||
}
|
||||
|
||||
type Rand interface {
|
||||
GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, filecoinEpoch abi.ChainEpoch, entropy []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type ApplyRet struct {
|
||||
|
@ -257,7 +257,8 @@ var importBenchCmd = &cli.Command{
|
||||
cs := store.NewChainStore(bs, bs, metadataDs, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule())
|
||||
// TODO: We need to supply the actual beacon after v14
|
||||
stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -741,7 +741,7 @@ var chainPledgeCmd = &cli.Command{
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
|
||||
lrand "github.com/filecoin-project/lotus/chain/rand"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
@ -78,7 +79,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S
|
||||
// 1. We don't charge a fee.
|
||||
// 2. The runtime has "fake" proof logic.
|
||||
// 3. We don't actually save any of the results.
|
||||
r := store.NewChainRand(sm.ChainStore(), parentTs.Cids())
|
||||
r := lrand.NewStateRand(sm.ChainStore(), parentTs.Cids(), sm.Beacon())
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: parentState,
|
||||
Epoch: parentTs.Height() + 1,
|
||||
|
@ -106,7 +106,7 @@ func (nd *Node) LoadSim(ctx context.Context, name string) (*Simulation, error) {
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err)
|
||||
}
|
||||
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us)
|
||||
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err)
|
||||
}
|
||||
@ -125,7 +125,7 @@ func (nd *Node) CreateSim(ctx context.Context, name string, head *types.TipSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule())
|
||||
sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("creating state manager: %w", err)
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ func (sim *Simulation) SetUpgradeHeight(nv network.Version, epoch abi.ChainEpoch
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule)
|
||||
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -44,8 +44,7 @@ func sectorsFromClaim(sectorSize abi.SectorSize, c power.Claim) int64 {
|
||||
}
|
||||
|
||||
func postChainCommitInfo(ctx context.Context, bb *blockbuilder.BlockBuilder, epoch abi.ChainEpoch) (abi.Randomness, error) {
|
||||
cs := bb.StateManager().ChainStore()
|
||||
ts := bb.ParentTipSet()
|
||||
commitRand, err := cs.GetChainRandomness(ctx, ts.Cids(), crypto.DomainSeparationTag_PoStChainCommit, epoch, nil, true)
|
||||
commitRand, err := bb.StateManager().GetRandomnessFromTickets(ctx, crypto.DomainSeparationTag_PoStChainCommit, epoch, nil, ts.Key())
|
||||
return commitRand, err
|
||||
}
|
||||
|
@ -520,7 +520,8 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
||||
return err
|
||||
}
|
||||
|
||||
stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule())
|
||||
// TODO: We need to supply the actual beacon after v14
|
||||
stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
||||
|
||||
cs = store.NewChainStore(bs, bs, ds, filcns.Weight, nil)
|
||||
tse = filcns.NewTipSetExecutor()
|
||||
sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule())
|
||||
sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule(), nil)
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -204,7 +204,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
|
||||
// dummy state manager; only to reference the GetNetworkVersion method,
|
||||
// which does not depend on state.
|
||||
sm, err := stmgr.NewStateManager(nil, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule())
|
||||
sm, err := stmgr.NewStateManager(nil, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return nil, cid.Cid{}, err
|
||||
}
|
||||
|
@ -19,18 +19,22 @@ func NewFixedRand() vm.Rand {
|
||||
return &fixedRand{}
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetChainRandomnessLookingForward(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
func (r *fixedRand) GetChainRandomnessV1(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetChainRandomnessLookingBack(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
func (r *fixedRand) GetChainRandomnessV2(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetBeaconRandomnessLookingForward(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
func (r *fixedRand) GetBeaconRandomnessV3(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetBeaconRandomnessLookingBack(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
func (r *fixedRand) GetBeaconRandomnessV1(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
||||
func (r *fixedRand) GetBeaconRandomnessV2(_ context.Context, _ crypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) ([]byte, error) {
|
||||
return []byte("i_am_random_____i_am_random_____"), nil // 32 bytes.
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ func (r *RecordingRand) loadHead() {
|
||||
r.head = head.Key()
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (r *RecordingRand) GetChainRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return r.getChainRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (r *RecordingRand) GetChainRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return r.getChainRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
@ -79,17 +79,21 @@ func (r *RecordingRand) getChainRandomness(ctx context.Context, pers crypto.Doma
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (r *RecordingRand) GetBeaconRandomnessV3(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return r.getBeaconRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
func (r *RecordingRand) GetBeaconRandomnessV1(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return r.getBeaconRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *RecordingRand) GetBeaconRandomnessV2(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return r.getBeaconRandomness(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *RecordingRand) getBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
r.once.Do(r.loadHead)
|
||||
ret, err := r.api.ChainGetRandomnessFromBeacon(ctx, r.head, pers, round, entropy)
|
||||
ret, err := r.api.StateGetRandomnessFromBeacon(ctx, pers, round, entropy, r.head)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
@ -43,11 +43,11 @@ func (r *ReplayingRand) match(requested schema.RandomnessRule) ([]byte, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (r *ReplayingRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
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) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -67,17 +67,21 @@ func (r *ReplayingRand) getChainRandomness(ctx context.Context, pers crypto.Doma
|
||||
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.GetChainRandomnessV1(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
return r.fallback.GetChainRandomnessLookingForward(ctx, pers, round, entropy)
|
||||
return r.fallback.GetChainRandomnessV2(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (r *ReplayingRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
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) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -97,8 +101,8 @@ func (r *ReplayingRand) getBeaconRandomness(ctx context.Context, pers crypto.Dom
|
||||
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.GetBeaconRandomnessV1(ctx, pers, round, entropy)
|
||||
}
|
||||
|
||||
return r.fallback.GetBeaconRandomnessLookingForward(ctx, pers, round, entropy)
|
||||
return r.fallback.GetBeaconRandomnessV3(ctx, pers, round, entropy)
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lrand "github.com/filecoin-project/lotus/chain/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/v1api"
|
||||
|
||||
proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof"
|
||||
@ -27,7 +29,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
|
||||
@ -525,7 +526,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (minedBlock *type
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
rand, err := lrand.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
if err != nil {
|
||||
err = xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
||||
return nil, err
|
||||
@ -590,7 +591,7 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas
|
||||
buf.Write(base.TipSet.MinTicket().VRFProof)
|
||||
}
|
||||
|
||||
input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes())
|
||||
input, err := lrand.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1422,32 +1422,10 @@ func (m *StateModule) StateNetworkVersion(ctx context.Context, tsk types.TipSetK
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := a.Chain.LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
||||
}
|
||||
|
||||
rnv := a.StateManager.GetNtwkVersion(ctx, randEpoch)
|
||||
|
||||
if rnv >= network.Version13 {
|
||||
return a.Chain.GetChainRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return a.Chain.GetChainRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
return a.StateManager.GetRandomnessFromTickets(ctx, personalization, randEpoch, entropy, tsk)
|
||||
}
|
||||
|
||||
func (a *StateAPI) StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error) {
|
||||
pts, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
|
||||
rnv := a.StateManager.GetNtwkVersion(ctx, randEpoch)
|
||||
|
||||
if rnv >= network.Version13 {
|
||||
return a.Chain.GetBeaconRandomnessLookingForward(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
}
|
||||
|
||||
return a.Chain.GetBeaconRandomnessLookingBack(ctx, pts.Cids(), personalization, randEpoch, entropy)
|
||||
return a.StateManager.GetRandomnessFromBeacon(ctx, personalization, randEpoch, entropy, tsk)
|
||||
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func NetworkName(mctx helpers.MetricsCtx,
|
||||
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us)
|
||||
sm, err := stmgr.NewStateManager(cs, tsexec, syscalls, us, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"go.uber.org/fx"
|
||||
|
||||
@ -8,8 +9,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
)
|
||||
|
||||
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule) (*stmgr.StateManager, error) {
|
||||
sm, err := stmgr.NewStateManager(cs, exec, sys, us)
|
||||
func StateManager(lc fx.Lifecycle, cs *store.ChainStore, exec stmgr.Executor, sys vm.SyscallBuilder, us stmgr.UpgradeSchedule, b beacon.Schedule) (*stmgr.StateManager, error) {
|
||||
sm, err := stmgr.NewStateManager(cs, exec, sys, us, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user