Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: drand quicknet: allow scheduling drand quicknet upgrade before nv22 on 2k devnet #11632

Merged
merged 5 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions build/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ type DrandEnum int

func DrandConfigSchedule() dtypes.DrandSchedule {
out := dtypes.DrandSchedule{}
for start, config := range DrandSchedule {
out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[config]})
for start, network := range DrandSchedule {
out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[network]})
}

sort.Slice(out, func(i, j int) bool {
Expand Down Expand Up @@ -44,6 +44,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"/dnsaddr/api2.drand.sh/",
"/dnsaddr/api3.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31","period":30,"genesis_time":1595431050,"hash":"8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce","groupHash":"176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a"}`,
},
DrandQuicknet: {
Expand All @@ -59,6 +60,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"/dnsaddr/api2.drand.sh/",
"/dnsaddr/api3.drand.sh/",
},
IsChained: false,
ChainInfoJSON: `{"public_key":"83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a","period":3,"genesis_time":1692803367,"hash":"52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971","groupHash":"f477d5c89f21a17c863a7f937c6a6d15859414d2be09cd448d4279af331c5d3e","schemeID":"bls-unchained-g1-rfc9380","metadata":{"beaconID":"quicknet"}}`,
},
DrandTestnet: {
Expand All @@ -72,6 +74,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"/dnsaddr/pl-us.testnet.drand.sh/",
"/dnsaddr/pl-sin.testnet.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`,
},
DrandDevnet: {
Expand All @@ -83,9 +86,11 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"/dnsaddr/dev1.drand.sh/",
"/dnsaddr/dev2.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
},
DrandIncentinet: {
IsChained: true,
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
},
}
24 changes: 23 additions & 1 deletion build/params_2k.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var NetworkBundle = "devnet"
var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = true

const GenesisNetworkVersion = network.Version21
var GenesisNetworkVersion = network.Version21

var UpgradeBreezeHeight = abi.ChainEpoch(-1)

Expand Down Expand Up @@ -96,6 +96,22 @@ func init() {
policy.SetMinVerifiedDealSize(MinVerifiedDealSize)
policy.SetPreCommitChallengeDelay(PreCommitChallengeDelay)

getGenesisNetworkVersion := func(ev string, def network.Version) network.Version {
hs, found := os.LookupEnv(ev)
if found {
h, err := strconv.Atoi(hs)
if err != nil {
log.Panicf("failed to parse %s env var", ev)
}

return network.Version(h)
}

return def
}

GenesisNetworkVersion = getGenesisNetworkVersion("LOTUS_GENESIS_NETWORK_VERSION", GenesisNetworkVersion)

getUpgradeHeight := func(ev string, def abi.ChainEpoch) abi.ChainEpoch {
hs, found := os.LookupEnv(ev)
if found {
Expand Down Expand Up @@ -136,6 +152,12 @@ func init() {
UpgradeWatermelonHeight = getUpgradeHeight("LOTUS_WATERMELON_HEIGHT", UpgradeWatermelonHeight)
UpgradeDragonHeight = getUpgradeHeight("LOTUS_DRAGON_HEIGHT", UpgradeDragonHeight)

UpgradePhoenixHeight = getUpgradeHeight("LOTUS_PHOENIX_HEIGHT", UpgradePhoenixHeight)
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
UpgradePhoenixHeight: DrandQuicknet,
}

BuildType |= Build2k

}
Expand Down
87 changes: 41 additions & 46 deletions chain/beacon/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,28 @@ type RandomBeacon interface {
Entry(context.Context, uint64) <-chan Response
VerifyEntry(entry types.BeaconEntry, prevEntrySig []byte) error
MaxBeaconRoundForEpoch(network.Version, abi.ChainEpoch) uint64
IsChained() bool
}

func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockHeader, parentEpoch abi.ChainEpoch,
prevEntry types.BeaconEntry) error {
// Before nv22 we had "chained" beacons, and so required two entries at a fork
if nv < network.Version22 {
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
currBeacon := bSchedule.BeaconForEpoch(h.Height)
if parentBeacon != currBeacon {
if len(h.BeaconEntries) != 2 {
return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries))
}
err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0].Data)
if err != nil {
return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w",
h.BeaconEntries[1], h.BeaconEntries[0], err)
}
return nil

parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
currBeacon := bSchedule.BeaconForEpoch(h.Height)
// When we have "chained" beacons, two entries at a fork are required.
if parentBeacon != currBeacon && currBeacon.IsChained() {
if len(h.BeaconEntries) != 2 {
return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries))
}
err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0].Data)
if err != nil {
return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w",
h.BeaconEntries[1], h.BeaconEntries[0], err)
}
return nil
}

b := bSchedule.BeaconForEpoch(h.Height)
maxRound := b.MaxBeaconRoundForEpoch(nv, h.Height)
maxRound := currBeacon.MaxBeaconRoundForEpoch(nv, h.Height)
// We don't expect to ever actually meet this condition
if maxRound == prevEntry.Round {
if len(h.BeaconEntries) != 0 {
Expand All @@ -80,8 +79,8 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH
return xerrors.Errorf("expected to have beacon entries in this block, but didn't find any")
}

if nv < network.Version22 && prevEntry.Round == 0 {
// We skip verifying the genesis entry before nv22, since that was "chained" randomness.
// We skip verifying the genesis entry when randomness is "chained".
if currBeacon.IsChained() && prevEntry.Round == 0 {
return nil
}

Expand All @@ -92,15 +91,15 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH

// Verify that all other entries' rounds are as expected for the epochs in between parentEpoch and h.Height
for i, e := range h.BeaconEntries {
correctRound := b.MaxBeaconRoundForEpoch(nv, parentEpoch+abi.ChainEpoch(i)+1)
correctRound := currBeacon.MaxBeaconRoundForEpoch(nv, parentEpoch+abi.ChainEpoch(i)+1)
if e.Round != correctRound {
return xerrors.Errorf("unexpected beacon round %d, expected %d for epoch %d", e.Round, correctRound, parentEpoch+abi.ChainEpoch(i))
}
}

// Verify the beacon entries themselves
for i, e := range h.BeaconEntries {
if err := b.VerifyEntry(e, prevEntry.Data); err != nil {
if err := currBeacon.VerifyEntry(e, prevEntry.Data); err != nil {
return xerrors.Errorf("beacon entry %d (%d - %x (%d)) was invalid: %w", i, e.Round, e.Data, len(e.Data), err)
}
prevEntry = e
Expand All @@ -110,35 +109,31 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH
}

func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, nv network.Version, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
// Before nv22 we had "chained" beacons, and so required two entries at a fork
if nv < network.Version22 {
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
currBeacon := bSchedule.BeaconForEpoch(epoch)
if parentBeacon != currBeacon {
// Fork logic
round := currBeacon.MaxBeaconRoundForEpoch(nv, epoch)
out := make([]types.BeaconEntry, 2)
rch := currBeacon.Entry(ctx, round-1)
res := <-rch
if res.Err != nil {
return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err)
}
out[0] = res.Entry
rch = currBeacon.Entry(ctx, round)
res = <-rch
if res.Err != nil {
return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err)
}
out[1] = res.Entry
return out, nil
// When we have "chained" beacons, two entries at a fork are required.
parentBeacon := bSchedule.BeaconForEpoch(parentEpoch)
currBeacon := bSchedule.BeaconForEpoch(epoch)
if parentBeacon != currBeacon && currBeacon.IsChained() {
// Fork logic
round := currBeacon.MaxBeaconRoundForEpoch(nv, epoch)
out := make([]types.BeaconEntry, 2)
rch := currBeacon.Entry(ctx, round-1)
res := <-rch
if res.Err != nil {
return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err)
}
out[0] = res.Entry
rch = currBeacon.Entry(ctx, round)
res = <-rch
if res.Err != nil {
return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err)
}
out[1] = res.Entry
return out, nil
}

beacon := bSchedule.BeaconForEpoch(epoch)

start := build.Clock.Now()

maxRound := beacon.MaxBeaconRoundForEpoch(nv, epoch)
maxRound := currBeacon.MaxBeaconRoundForEpoch(nv, epoch)
// We don't expect this to ever be the case
if maxRound == prev.Round {
return nil, nil
Expand All @@ -151,8 +146,8 @@ func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, nv network.V

var out []types.BeaconEntry
for currEpoch := epoch; currEpoch > parentEpoch; currEpoch-- {
currRound := beacon.MaxBeaconRoundForEpoch(nv, currEpoch)
rch := beacon.Entry(ctx, currRound)
currRound := currBeacon.MaxBeaconRoundForEpoch(nv, currEpoch)
rch := currBeacon.Entry(ctx, currRound)
select {
case resp := <-rch:
if resp.Err != nil {
Expand Down
8 changes: 7 additions & 1 deletion chain/beacon/drand/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ var log = logging.Logger("drand")
//
// The root trust for the Drand chain is configured from build.DrandChain.
type DrandBeacon struct {
client dclient.Client
isChained bool
client dclient.Client

pubkey kyber.Point

Expand All @@ -52,6 +53,10 @@ type DrandBeacon struct {
localCache *lru.Cache[uint64, *types.BeaconEntry]
}

func (db *DrandBeacon) IsChained() bool {
return db.isChained
}

// DrandHTTPClient interface overrides the user agent used by drand
type DrandHTTPClient interface {
SetUserAgent(string)
Expand Down Expand Up @@ -117,6 +122,7 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes
}

db := &DrandBeacon{
isChained: config.IsChained,
client: client,
localCache: lc,
}
Expand Down
8 changes: 8 additions & 0 deletions chain/beacon/drand/drand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,15 @@ func TestMaxBeaconRoundForEpoch(t *testing.T) {
todayTs := uint64(1652222222)
db, err := NewDrandBeacon(todayTs, build.BlockDelaySecs, nil, build.DrandConfigs[build.DrandTestnet])
assert.NoError(t, err)
assert.True(t, db.IsChained())
mbr15 := db.MaxBeaconRoundForEpoch(network.Version15, 100)
mbr16 := db.MaxBeaconRoundForEpoch(network.Version16, 100)
assert.Equal(t, mbr15+1, mbr16)
}

func TestQuicknetIsChained(t *testing.T) {
todayTs := uint64(1652222222)
db, err := NewDrandBeacon(todayTs, build.BlockDelaySecs, nil, build.DrandConfigs[build.DrandQuicknet])
assert.NoError(t, err)
assert.False(t, db.IsChained())
}
4 changes: 4 additions & 0 deletions chain/beacon/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ type mockBeacon struct {
interval time.Duration
}

func (mb *mockBeacon) IsChained() bool {
return true
}

func NewMockBeacon(interval time.Duration) RandomBeacon {
mb := &mockBeacon{interval: interval}

Expand Down
1 change: 1 addition & 0 deletions node/modules/dtypes/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ type DrandConfig struct {
Servers []string
Relays []string
ChainInfoJSON string
IsChained bool
}