Skip to content

Commit

Permalink
feat: drand quicknet: allow scheduling drand quicknet upgrade before …
Browse files Browse the repository at this point in the history
…nv22 on 2k devnet
  • Loading branch information
simlecode committed Mar 1, 2024
1 parent f133400 commit 2035014
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 50 deletions.
88 changes: 41 additions & 47 deletions pkg/beacon/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,30 @@ type RandomBeacon interface {
// VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
VerifyEntry(entry types.BeaconEntry, prevEntrySig []byte) error
MaxBeaconRoundForEpoch(network.Version, abi.ChainEpoch) uint64
IsChained() bool
}

// ValidateBlockValues Verify that the beacon in the block header is correct, first get beacon server at block epoch and parent block epoch in schedule.
// if paraent beacon is the same beacon server. value beacon normally but if not equal, means that the pre entry in another beacon chain, so just validate
// beacon value in current block header. the first values is parent beacon the the second value is current beacon.
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 fmt.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 fmt.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 fmt.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 fmt.Errorf("beacon at fork point invalid: (%v, %v): %w",
h.BeaconEntries[1], h.BeaconEntries[0], err)
}
return nil
}

// TODO: fork logic
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 @@ -70,8 +68,8 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH
return fmt.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 @@ -82,15 +80,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 fmt.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 fmt.Errorf("beacon entry %d (%d - %x (%d)) was invalid: %w", i, e.Round, e.Data, len(e.Data), err)
}
prevEntry = &h.BeaconEntries[i]
Expand All @@ -100,35 +98,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) { //nolint
// 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, fmt.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, fmt.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, fmt.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, fmt.Errorf("getting entry %d returned error: %w", round, res.Err)
}
out[1] = res.Entry
return out, nil
}

beacon := bSchedule.BeaconForEpoch(epoch)

start := time.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 @@ -141,8 +135,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 pkg/beacon/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import (
//
// 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 @@ -46,6 +47,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 @@ -104,6 +109,7 @@ func NewDrandBeacon(genTimeStamp, interval uint64, config cfg.DrandConf) (*Drand
}

db := &DrandBeacon{
isChained: config.IsChained,
client: client,
localCache: lc,
}
Expand Down
10 changes: 10 additions & 0 deletions pkg/beacon/drand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,17 @@ func TestMaxBeaconRoundForEpoch(t *testing.T) {
drandCfg := config.DrandConfigs[config.DrandDevnet]
db, err := NewDrandBeacon(todayTS, config.NewDefaultConfig().NetworkParams.BlockDelay, drandCfg)
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) {
tf.UnitTest(t)
todayTS := uint64(1652222222)
drandCfg := config.DrandConfigs[config.DrandQuicknet]
db, err := NewDrandBeacon(todayTS, config.NewDefaultConfig().NetworkParams.BlockDelay, drandCfg)
assert.NoError(t, err)
assert.False(t, db.IsChained())
}
4 changes: 4 additions & 0 deletions pkg/beacon/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func NewMockSchedule(interval time.Duration) Schedule {
}}
}

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

func (mb *mockBeacon) RoundTime() time.Duration {
return mb.interval
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/beacon_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type DrandConf struct {
Servers []string
Relays []string
ChainInfoJSON string
IsChained bool
}

// DrandConfigs a set of drand config
Expand All @@ -32,6 +33,7 @@ var DrandConfigs = map[DrandEnum]DrandConf{
"/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 @@ -47,6 +49,7 @@ var DrandConfigs = map[DrandEnum]DrandConf{
"/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 @@ -58,6 +61,7 @@ var DrandConfigs = map[DrandEnum]DrandConf{
"/dnsaddr/pl-eu.testnet.drand.sh/",
"/dnsaddr/pl-us.testnet.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`,
},
DrandDevnet: {
Expand All @@ -69,6 +73,7 @@ var DrandConfigs = map[DrandEnum]DrandConf{
"/dnsaddr/dev1.drand.sh/",
"/dnsaddr/dev2.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
},
DrandIncentinet: {
Expand All @@ -82,6 +87,7 @@ var DrandConfigs = map[DrandEnum]DrandConf{
"/dnsaddr/pl-us.incentinet.drand.sh/",
"/dnsaddr/pl-sin.incentinet.drand.sh/",
},
IsChained: true,
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
},
}
4 changes: 2 additions & 2 deletions pkg/testhelpers/test_daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,9 @@ func (td *TestDaemon) WaitForAPI() error {
if err == nil {
return nil
}
time.Sleep(time.Millisecond * 100)
time.Sleep(time.Second * 20)
}
return fmt.Errorf("filecoin node failed to come online in given time period (10 seconds); last err = %s", err)
return fmt.Errorf("filecoin node failed to come online in given time period (20 seconds); last err = %s", err)
}

// CreateStorageMinerAddr issues a new message to the network, mines the message
Expand Down

0 comments on commit 2035014

Please sign in to comment.