diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 4d864c73e..d44b30ebc 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -552,7 +552,7 @@ func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, pers return nil, xerrors.Errorf("loading tipset key: %w", err) } - return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy) + return mca.sm.ChainStore().GetChainRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy) } func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) { diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 37b3d53e0..acf4e154e 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -318,7 +318,13 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid // TODO: copied from actors test harness, deduplicate or remove from here type fakeRand struct{} -func (fr *fakeRand) GetRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { +func (fr *fakeRand) GetChainRandomness(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) + return out, nil +} + +func (fr *fakeRand) GetBeaconRandomness(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) return out, nil diff --git a/chain/store/store.go b/chain/store/store.go index 2665d0298..d34fdbe5f 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -994,8 +994,42 @@ func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.Cha return h.Sum(nil), nil } -func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - _, span := trace.StartSpan(ctx, "store.GetRandomness") +func (cs *ChainStore) GetBeaconRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]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, true) + 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) GetChainRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + _, span := trace.StartSpan(ctx, "store.GetChainRandomness") defer span.End() span.AddAttributes(trace.Int64Attribute("round", int64(round))) @@ -1236,8 +1270,12 @@ func NewChainRand(cs *ChainStore, blks []cid.Cid, bheight abi.ChainEpoch) vm.Ran } } -func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return cr.cs.GetRandomness(ctx, cr.blks, pers, round, entropy) +func (cr *chainRand) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return cr.cs.GetChainRandomness(ctx, cr.blks, pers, round, entropy) +} + +func (cr *chainRand) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { + return cr.cs.GetBeaconRandomness(ctx, cr.blks, pers, round, entropy) } func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) { diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 3267feccd..ec47245d6 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -72,7 +72,7 @@ func BenchmarkGetRandomness(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := cs.GetRandomness(context.TODO(), last.Cids(), crypto.DomainSeparationTag_SealRandomness, 500, nil) + _, err := cs.GetChainRandomness(context.TODO(), last.Cids(), crypto.DomainSeparationTag_SealRandomness, 500, nil) if err != nil { b.Fatal(err) } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 5da28006c..7119ec69c 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -231,8 +231,16 @@ func (rt *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) return act.Code, true } -func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { - res, err := rt.vm.rand.GetRandomness(rt.ctx, personalization, randEpoch, entropy) +func (rt *Runtime) GetRandomnessFromTickets(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { + res, err := rt.vm.rand.GetChainRandomness(rt.ctx, personalization, randEpoch, entropy) + if err != nil { + panic(aerrors.Fatalf("could not get randomness: %s", err)) + } + return res +} + +func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { + res, err := rt.vm.rand.GetBeaconRandomness(rt.ctx, personalization, randEpoch, entropy) if err != nil { panic(aerrors.Fatalf("could not get randomness: %s", err)) } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 807edae41..214378613 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -189,7 +189,8 @@ func NewVM(opts *VMOpts) (*VM, error) { } type Rand interface { - GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) + GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) } type ApplyRet struct { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 53495bde4..ab4389fa9 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -60,7 +60,7 @@ func (a *ChainAPI) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, return nil, xerrors.Errorf("loading tipset key: %w", err) } - return a.Chain.GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy) + return a.Chain.GetChainRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy) } func (a *ChainAPI) ChainGetBlock(ctx context.Context, msg cid.Cid) (*types.BlockHeader, error) {