diff --git a/chain/beacon/mock.go b/chain/beacon/mock.go index 502ff2ba5..2fc64b956 100644 --- a/chain/beacon/mock.go +++ b/chain/beacon/mock.go @@ -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) diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index e02c96096..927562840 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -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 { diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index 43226544e..7abd2cb77 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -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) } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 6f111a69e..b7d49f278 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -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) } diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index f79d41824..2a6c68326 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -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 diff --git a/chain/rand/rand.go b/chain/rand/rand.go new file mode 100644 index 000000000..90e9a514b --- /dev/null +++ b/chain/rand/rand.go @@ -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) +} diff --git a/chain/rand/rand_test.go b/chain/rand/rand_test.go new file mode 100644 index 000000000..5e5dae3f1 --- /dev/null +++ b/chain/rand/rand_test.go @@ -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") + } +} diff --git a/chain/stmgr/actors.go b/chain/stmgr/actors.go index 0c1e219c8..4d016b7ab 100644 --- a/chain/stmgr/actors.go +++ b/chain/stmgr/actors.go @@ -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) } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 6a0186715..7cc50e710 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -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( diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index a3e35da4b..4fad1e4fc 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -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) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 4a0f89141..49a90d99f 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -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) +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 42ef56e04..ce4f60105 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -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, diff --git a/chain/store/rand.go b/chain/store/rand.go deleted file mode 100644 index 1fa9e678f..000000000 --- a/chain/store/rand.go +++ /dev/null @@ -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) -} diff --git a/chain/store/store.go b/chain/store/store.go index 733f25c32..f99c7f649 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -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") +} diff --git a/chain/store/store_test.go b/chain/store/store_test.go index b393e8eb2..2004b266c 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -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) } diff --git a/chain/sync_test.go b/chain/sync_test.go index 0e4f3fd7a..4175ff5fa 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -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) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 6118eb2fa..29b987c00 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -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 { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 80bad39dc..36308fe03 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -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 { diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 7047866cb..c66b90deb 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -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 } diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index 0de2e03b4..1a22be3c3 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -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 } diff --git a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go index 1abf940e3..a6353e4f4 100644 --- a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go +++ b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go @@ -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, diff --git a/cmd/lotus-sim/simulation/node.go b/cmd/lotus-sim/simulation/node.go index 22463512a..c18f27a33 100644 --- a/cmd/lotus-sim/simulation/node.go +++ b/cmd/lotus-sim/simulation/node.go @@ -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) } diff --git a/cmd/lotus-sim/simulation/simulation.go b/cmd/lotus-sim/simulation/simulation.go index 56030fa23..02792e332 100644 --- a/cmd/lotus-sim/simulation/simulation.go +++ b/cmd/lotus-sim/simulation/simulation.go @@ -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 } diff --git a/cmd/lotus-sim/simulation/stages/util.go b/cmd/lotus-sim/simulation/stages/util.go index 97c1e57af..0c17823c0 100644 --- a/cmd/lotus-sim/simulation/stages/util.go +++ b/cmd/lotus-sim/simulation/stages/util.go @@ -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 } diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 51aeca3c4..3f5de8138 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -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 } diff --git a/conformance/driver.go b/conformance/driver.go index 6fef5a76d..8669089da 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -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 } diff --git a/conformance/rand_fixed.go b/conformance/rand_fixed.go index f15910e1d..c34980efe 100644 --- a/conformance/rand_fixed.go +++ b/conformance/rand_fixed.go @@ -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. } diff --git a/conformance/rand_record.go b/conformance/rand_record.go index 906d6b73d..97bd93eb4 100644 --- a/conformance/rand_record.go +++ b/conformance/rand_record.go @@ -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 } diff --git a/conformance/rand_replay.go b/conformance/rand_replay.go index faae1d090..5d850f7eb 100644 --- a/conformance/rand_replay.go +++ b/conformance/rand_replay.go @@ -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) } diff --git a/miner/miner.go b/miner/miner.go index 1727f6942..582ade723 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -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 } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 2981c0162..e251fa3d5 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -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) } diff --git a/node/modules/chain.go b/node/modules/chain.go index f9baf76cf..3518c3b29 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -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 } diff --git a/node/modules/stmgr.go b/node/modules/stmgr.go index d2f812ad4..daef52b42 100644 --- a/node/modules/stmgr.go +++ b/node/modules/stmgr.go @@ -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 }