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: implement FIP-0063 #11572

Merged
merged 1 commit into from
Jan 29, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions build/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
DrandDevnet
DrandLocalnet
DrandIncentinet
DrandQuicknet
)

var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
Expand All @@ -36,6 +37,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"https://api2.drand.sh",
"https://api3.drand.sh",
"https://drand.cloudflare.com",
"https://api.drand.secureweb3.com:6875", // Storswift
},
Relays: []string{
"/dnsaddr/api.drand.sh/",
Expand All @@ -44,6 +46,21 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
},
ChainInfoJSON: `{"public_key":"868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31","period":30,"genesis_time":1595431050,"hash":"8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce","groupHash":"176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a"}`,
},
DrandQuicknet: {
Servers: []string{
"https://api.drand.sh",
arajasek marked this conversation as resolved.
Show resolved Hide resolved
"https://api2.drand.sh",
"https://api3.drand.sh",
"https://drand.cloudflare.com",
"https://api.drand.secureweb3.com:6875", // Storswift
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this endpoint monitored by any of the drand monitoring infra? We were burned in the past by 3rd party bootstrappers going offline.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the endpoint, no, though we get some alerting if their node goes down (which is normally a good indicator).
The client uses all the addresses as fallback so it shouldn’t cause an outage though - what was the issue in the past?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general issue in the past was that we had a significant number of third-party bootstrappers (let's say 70% of all), and the majority of them were down.

It didn't cause an outage per se, but it slowed down bootstraping.

},
Relays: []string{
"/dnsaddr/api.drand.sh/",
"/dnsaddr/api2.drand.sh/",
"/dnsaddr/api3.drand.sh/",
},
ChainInfoJSON: `{"public_key":"83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a","period":3,"genesis_time":1692803367,"hash":"52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971","groupHash":"f477d5c89f21a17c863a7f937c6a6d15859414d2be09cd448d4279af331c5d3e","schemeID":"bls-unchained-g1-rfc9380","metadata":{"beaconID":"quicknet"}}`,
},
DrandTestnet: {
Servers: []string{
"https://pl-eu.testnet.drand.sh",
Expand Down
7 changes: 5 additions & 2 deletions build/params_2k.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ var UpgradeThunderHeight = abi.ChainEpoch(-23)

var UpgradeWatermelonHeight = abi.ChainEpoch(-24)

var UpgradePineappleHeight = abi.ChainEpoch(200)
var UpgradePineappleHeight = abi.ChainEpoch(20)

var UpgradeMangoHeight = UpgradePineappleHeight + 10

// This fix upgrade only ran on calibrationnet
const UpgradeWatermelonFixHeight = -100
Expand All @@ -76,7 +78,8 @@ const UpgradeWatermelonFixHeight = -100
const UpgradeWatermelonFix2Height = -101

var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

var SupportedProofTypes = []abi.RegisteredSealProof{
Expand Down
5 changes: 4 additions & 1 deletion build/params_butterfly.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
)

var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

const GenesisNetworkVersion = network.Version20
Expand Down Expand Up @@ -59,6 +60,8 @@ const UpgradeWatermelonHeight = -24
// ??????
const UpgradePineappleHeight = 999999999999999

const UpgradeMangoHeight = UpgradePineappleHeight + 10

// This fix upgrade only ran on calibrationnet
const UpgradeWatermelonFixHeight = -100

Expand Down
5 changes: 4 additions & 1 deletion build/params_calibnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import (
)

var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

const GenesisNetworkVersion = network.Version0
Expand Down Expand Up @@ -91,6 +92,8 @@ const UpgradeWatermelonFix2Height = 1108174
// ??????
const UpgradePineappleHeight = 999999999999999

const UpgradeMangoHeight = UpgradePineappleHeight + 10

var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
Expand Down
5 changes: 4 additions & 1 deletion build/params_interop.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,17 @@ var UpgradeWatermelonHeight = abi.ChainEpoch(-24)

const UpgradePineappleHeight = 50

const UpgradeMangoHeight = UpgradePineappleHeight + 10

// This fix upgrade only ran on calibrationnet
const UpgradeWatermelonFixHeight = -1

// This fix upgrade only ran on calibrationnet
const UpgradeWatermelonFix2Height = -2

var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

var SupportedProofTypes = []abi.RegisteredSealProof{
Expand Down
8 changes: 7 additions & 1 deletion build/params_mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandIncentinet,
UpgradeSmokeHeight: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

var NetworkBundle = "mainnet"
Expand Down Expand Up @@ -101,6 +102,10 @@ const UpgradeWatermelonHeight = 3469380
// ??????
var UpgradePineappleHeight = abi.ChainEpoch(999999999999999)

// This epoch, 10 epochs after the "rest" of the nv22 upgrade, is when we switch to Drand quicknet
// ??????
var UpgradeMangoHeight = UpgradePineappleHeight + 10

// This fix upgrade only ran on calibrationnet
const UpgradeWatermelonFixHeight = -1

Expand All @@ -123,7 +128,8 @@ func init() {
}

if os.Getenv("LOTUS_DISABLE_PINEAPPLE") == "1" {
UpgradePineappleHeight = math.MaxInt64
UpgradePineappleHeight = math.MaxInt64 - 1
UpgradeMangoHeight = math.MaxInt64
}

// NOTE: DO NOT change this unless you REALLY know what you're doing. This is not consensus critical, however,
Expand Down
4 changes: 3 additions & 1 deletion build/params_testground.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,11 @@ var (
UpgradeWatermelonFixHeight abi.ChainEpoch = -24
UpgradeWatermelonFix2Height abi.ChainEpoch = -25
UpgradePineappleHeight abi.ChainEpoch = -26
UpgradeMangoHeight abi.ChainEpoch = -27

DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandMainnet,
UpgradeMangoHeight: DrandQuicknet,
}

GenesisNetworkVersion = network.Version0
Expand Down
21 changes: 14 additions & 7 deletions chain/beacon/beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,21 @@ type BeaconPoint struct {
// been posted on chain.
type RandomBeacon interface {
Entry(context.Context, uint64) <-chan Response
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
VerifyEntry(entry types.BeaconEntry, prevEntrySig []byte) error
MaxBeaconRoundForEpoch(network.Version, abi.ChainEpoch) uint64
}

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If drand network upgrade does not align with chain network upgrade, should we check the exact drand network upgrade epoch here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fork logic which works off the DrandSchedule. So, the meaning of this is to disable the old fork logic before switching to the new Drand network.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hanabi1224 Thanks for the question! I don't think we need to check the exact epoch here -- as Kuba said, the intention is to say "before nv22, special-case fork logic this way". For the upcoming change to quicknet, we DON'T want to use the old fork logic, and instead just seamlessly switch to quicknet.

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])
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)
Expand All @@ -65,9 +66,9 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH
}
}

// TODO: fork logic
b := bSchedule.BeaconForEpoch(h.Height)
maxRound := b.MaxBeaconRoundForEpoch(nv, h.Height)
// We don't expect to ever actually meet this condition
if maxRound == prevEntry.Round {
if len(h.BeaconEntries) != 0 {
return xerrors.Errorf("expected not to have any beacon entries in this block, got %d", len(h.BeaconEntries))
Expand All @@ -79,7 +80,11 @@ 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")
}

// Verify that the last beacon entry's round corresponds to the round we expect
if nv < network.Version22 && prevEntry.Round == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, should we decouple drand network version and chain network version here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, I don't think so, no. From nv22 onwards we'll be using "unchained" randomness, and so can simply verify round 0 too.

// We skip verifying the genesis entry before nv22, since that was "chained" randomness.
return nil
}

last := h.BeaconEntries[len(h.BeaconEntries)-1]
if last.Round != maxRound {
return xerrors.Errorf("expected final beacon entry in block to be at round %d, got %d", maxRound, last.Round)
Expand All @@ -95,7 +100,7 @@ func ValidateBlockValues(bSchedule Schedule, nv network.Version, h *types.BlockH

// Verify the beacon entries themselves
for i, e := range h.BeaconEntries {
if err := b.VerifyEntry(e, prevEntry); err != nil {
if err := b.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 @@ -105,7 +110,8 @@ 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 {
Expand Down Expand Up @@ -133,6 +139,7 @@ func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, nv network.V
start := build.Clock.Now()

maxRound := beacon.MaxBeaconRoundForEpoch(nv, epoch)
// We don't expect this to ever be the case
if maxRound == prev.Round {
return nil, nil
}
Expand Down
38 changes: 23 additions & 15 deletions chain/beacon/drand/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
dchain "github.com/drand/drand/chain"
dclient "github.com/drand/drand/client"
hclient "github.com/drand/drand/client/http"
"github.com/drand/drand/common/scheme"
dcrypto "github.com/drand/drand/crypto"
dlog "github.com/drand/drand/log"
gclient "github.com/drand/drand/lp2p/client"
"github.com/drand/kyber"
Expand Down Expand Up @@ -47,6 +47,7 @@ type DrandBeacon struct {
drandGenTime uint64
filGenTime uint64
filRoundTime uint64
scheme *dcrypto.Scheme

localCache *lru.Cache[uint64, *types.BeaconEntry]
}
Expand All @@ -68,6 +69,10 @@ func (l *logger) Named(s string) dlog.Logger {
return &logger{l.SugaredLogger.Named(s)}
}

func (l *logger) AddCallerSkip(skip int) dlog.Logger {
arajasek marked this conversation as resolved.
Show resolved Hide resolved
return &logger{l.SugaredLogger.With(zap.AddCallerSkip(skip))}
}

func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes.DrandConfig) (*DrandBeacon, error) {
if genesisTs == 0 {
panic("what are you doing this cant be zero")
Expand Down Expand Up @@ -116,6 +121,11 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub, config dtypes
localCache: lc,
}

sch, err := dcrypto.GetSchemeByIDWithDefault(drandChain.Scheme)
if err != nil {
return nil, err
}
db.scheme = sch
db.pubkey = drandChain.PublicKey
db.interval = drandChain.Period
db.drandGenTime = uint64(drandChain.GenesisTime)
Expand Down Expand Up @@ -164,29 +174,27 @@ func (db *DrandBeacon) getCachedValue(round uint64) *types.BeaconEntry {
return v
}

func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntry) error {
if prev.Round == 0 {
// TODO handle genesis better
return nil
}

if be := db.getCachedValue(curr.Round); be != nil {
if !bytes.Equal(curr.Data, be.Data) {
func (db *DrandBeacon) VerifyEntry(entry types.BeaconEntry, prevEntrySig []byte) error {
if be := db.getCachedValue(entry.Round); be != nil {
if !bytes.Equal(entry.Data, be.Data) {
return xerrors.New("invalid beacon value, does not match cached good value")
}
// return no error if the value is in the cache already
return nil
}
b := &dchain.Beacon{
PreviousSig: prev.Data,
Round: curr.Round,
Signature: curr.Data,
PreviousSig: prevEntrySig,
Round: entry.Round,
Signature: entry.Data,
}
err := dchain.NewVerifier(scheme.GetSchemeFromEnv()).VerifyBeacon(*b, db.pubkey)
if err == nil {
db.cacheValue(curr)

err := db.scheme.VerifyBeacon(b, db.pubkey)
if err != nil {
return xerrors.Errorf("failed to verify beacon: %w", err)
}

db.cacheValue(entry)

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion chain/beacon/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (mb *mockBeacon) Entry(ctx context.Context, index uint64) <-chan Response {
return out
}

func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry) error {
func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, _prevEntrySig []byte) error {
// TODO: cache this, especially for bls
oe := mb.entryForIndex(from.Round)
if !bytes.Equal(from.Data, oe.Data) {
Expand Down
1 change: 1 addition & 0 deletions chain/consensus/filcns/filecoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
return xerrors.Errorf("failed to get lookback tipset for block: %w", err)
}

// TODO: Optimization: See https://github.com/filecoin-project/lotus/issues/11597
prevBeacon, err := filec.store.GetLatestBeaconEntry(ctx, baseTs)
if err != nil {
return xerrors.Errorf("failed to get latest beacon entry: %w", err)
Expand Down