lotus/chain/rand/rand_test.go
2021-12-10 11:41:24 +01:00

249 lines
6.4 KiB
Go

//stm:#unit
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
//stm: @BLOCKCHAIN_RAND_GET_BEACON_RANDOMNESS_V1_01, @BLOCKCHAIN_RAND_EXTRACT_BEACON_ENTRY_FOR_EPOCH_01, @BLOCKCHAIN_RAND_GET_BEACON_RANDOMNESS_TIPSET_02
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
if err != nil {
t.Fatal(err)
}
//stm: @BLOCKCHAIN_BEACON_GET_BEACON_FOR_EPOCH_01
bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(beforeNullHeight)+offset)
select {
case resp := <-bch:
if resp.Err != nil {
t.Fatal(resp.Err)
}
//stm: @BLOCKCHAIN_RAND_DRAW_RANDOMNESS_01
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
//stm: @BLOCKCHAIN_RAND_GET_BEACON_RANDOMNESS_V2_01
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
if err != nil {
t.Fatal(err)
}
//stm: @BLOCKCHAIN_BEACON_GET_BEACON_FOR_EPOCH_01
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)
}
//stm: @BLOCKCHAIN_RAND_DRAW_RANDOMNESS_01, @BLOCKCHAIN_RAND_EXTRACT_BEACON_ENTRY_FOR_EPOCH_01, @BLOCKCHAIN_RAND_GET_BEACON_RANDOMNESS_TIPSET_03
// 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
//stm: @BLOCKCHAIN_RAND_GET_BEACON_RANDOMNESS_V3_01, @BLOCKCHAIN_RAND_EXTRACT_BEACON_ENTRY_FOR_EPOCH_01
rand1, err := cg.StateManager().GetRandomnessFromBeacon(ctx, pers, randEpoch, entropy, ts.TipSet.TipSet().Key())
if err != nil {
t.Fatal(err)
}
//stm: @BLOCKCHAIN_BEACON_GET_BEACON_FOR_EPOCH_01
bch := cg.BeaconSchedule().BeaconForEpoch(randEpoch).Entry(ctx, uint64(randEpoch)+offset)
select {
case resp := <-bch:
if resp.Err != nil {
t.Fatal(resp.Err)
}
//stm: @BLOCKCHAIN_RAND_DRAW_RANDOMNESS_01
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")
}
}