Skip to content

Commit

Permalink
Sync primary network checkpoints during bootstrapping (#2752)
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Buttolph <stephen@avalabs.org>
Co-authored-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
  • Loading branch information
StephenButtolph and joshua-kim authored Apr 17, 2024
1 parent 7975cb7 commit 389a4ee
Show file tree
Hide file tree
Showing 10 changed files with 3,445 additions and 21 deletions.
35 changes: 35 additions & 0 deletions genesis/checkpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package genesis

import (
"encoding/json"
"fmt"

_ "embed"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/set"
)

var (
//go:embed checkpoints.json
checkpointsPerNetworkJSON []byte

checkpointsPerNetwork map[string]map[ids.ID]set.Set[ids.ID]
)

func init() {
if err := json.Unmarshal(checkpointsPerNetworkJSON, &checkpointsPerNetwork); err != nil {
panic(fmt.Sprintf("failed to decode checkpoints.json: %v", err))
}
}

// GetCheckpoints returns all known checkpoints for the chain on the requested
// network.
func GetCheckpoints(networkID uint32, chainID ids.ID) set.Set[ids.ID] {
networkName := constants.NetworkIDToNetworkName[networkID]
return checkpointsPerNetwork[networkName][chainID]
}
612 changes: 612 additions & 0 deletions genesis/checkpoints.json

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions genesis/generate/checkpoints/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
"context"
"encoding/json"
"fmt"
"log"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/indexer"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/set"
)

const (
fujiURI = "http://localhost:9650"
mainnetURI = "http://localhost:9660"

maxNumCheckpoints = 100
)

var (
fujiXChainID = ids.FromStringOrPanic("2JVSBoinj9C2J33VntvzYtVJNZdN2NKiwwKjcumHUWEb5DbBrm")
fujiCChainID = ids.FromStringOrPanic("yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp")
mainnetXChainID = ids.FromStringOrPanic("2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM")
mainnetCChainID = ids.FromStringOrPanic("2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5")
)

// This fetches IDs of blocks periodically accepted on the P-chain, X-chain, and
// C-chain on both Fuji and Mainnet.
//
// This expects to be able to communicate with a Fuji node at [fujiURI] and a
// Mainnet node at [mainnetURI]. Both nodes must have the index API enabled.
func main() {
ctx := context.Background()

fujiPChainCheckpoints, err := getCheckpoints(ctx, fujiURI, "P")
if err != nil {
log.Fatalf("failed to fetch Fuji P-chain checkpoints: %v", err)
}
fujiXChainCheckpoints, err := getCheckpoints(ctx, fujiURI, "X")
if err != nil {
log.Fatalf("failed to fetch Fuji X-chain checkpoints: %v", err)
}
fujiCChainCheckpoints, err := getCheckpoints(ctx, fujiURI, "C")
if err != nil {
log.Fatalf("failed to fetch Fuji C-chain checkpoints: %v", err)
}

mainnetPChainCheckpoints, err := getCheckpoints(ctx, mainnetURI, "P")
if err != nil {
log.Fatalf("failed to fetch Mainnet P-chain checkpoints: %v", err)
}
mainnetXChainCheckpoints, err := getCheckpoints(ctx, mainnetURI, "X")
if err != nil {
log.Fatalf("failed to fetch Mainnet X-chain checkpoints: %v", err)
}
mainnetCChainCheckpoints, err := getCheckpoints(ctx, mainnetURI, "C")
if err != nil {
log.Fatalf("failed to fetch Mainnet C-chain checkpoints: %v", err)
}

checkpoints := map[string]map[ids.ID]set.Set[ids.ID]{
constants.FujiName: {
constants.PlatformChainID: fujiPChainCheckpoints,
fujiXChainID: fujiXChainCheckpoints,
fujiCChainID: fujiCChainCheckpoints,
},
constants.MainnetName: {
constants.PlatformChainID: mainnetPChainCheckpoints,
mainnetXChainID: mainnetXChainCheckpoints,
mainnetCChainID: mainnetCChainCheckpoints,
},
}
checkpointsJSON, err := json.MarshalIndent(checkpoints, "", "\t")
if err != nil {
log.Fatalf("failed to marshal checkpoints: %v", err)
}

if err := perms.WriteFile("checkpoints.json", checkpointsJSON, perms.ReadWrite); err != nil {
log.Fatalf("failed to write checkpoints: %v", err)
}
}

func getCheckpoints(
ctx context.Context,
uri string,
chainAlias string,
) (set.Set[ids.ID], error) {
var (
chainURI = fmt.Sprintf("%s/ext/index/%s/block", uri, chainAlias)
client = indexer.NewClient(chainURI)
)

// If there haven't been any blocks accepted, this will return an error.
_, lastIndex, err := client.GetLastAccepted(ctx)
if err != nil {
return nil, err
}

var (
numAccepted = lastIndex + 1
// interval is rounded up to ensure that the number of checkpoints
// fetched is at most maxNumCheckpoints.
interval = (numAccepted + maxNumCheckpoints - 1) / maxNumCheckpoints
checkpoints set.Set[ids.ID]
)
for index := interval - 1; index <= lastIndex; index += interval {
container, err := client.GetContainerByIndex(ctx, index)
if err != nil {
return nil, err
}

checkpoints.Add(container.ID)
}
return checkpoints, nil
}
63 changes: 63 additions & 0 deletions genesis/generate/validators/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
"context"
"encoding/json"
"log"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm"
"github.com/ava-labs/avalanchego/wallet/subnet/primary"
)

// This fetches the current validator set of both Fuji and Mainnet.
func main() {
ctx := context.Background()

fujiValidators, err := getCurrentValidators(ctx, primary.FujiAPIURI)
if err != nil {
log.Fatalf("failed to fetch Fuji validators: %v", err)
}

mainnetValidators, err := getCurrentValidators(ctx, primary.MainnetAPIURI)
if err != nil {
log.Fatalf("failed to fetch Mainnet validators: %v", err)
}

validators := map[string]set.Set[ids.NodeID]{
constants.FujiName: fujiValidators,
constants.MainnetName: mainnetValidators,
}
validatorsJSON, err := json.MarshalIndent(validators, "", "\t")
if err != nil {
log.Fatalf("failed to marshal validators: %v", err)
}

if err := perms.WriteFile("validators.json", validatorsJSON, perms.ReadWrite); err != nil {
log.Fatalf("failed to write validators: %v", err)
}
}

func getCurrentValidators(ctx context.Context, uri string) (set.Set[ids.NodeID], error) {
client := platformvm.NewClient(uri)
currentValidators, err := client.GetCurrentValidators(
ctx,
constants.PrimaryNetworkID,
nil, // fetch all validators
)
if err != nil {
return nil, err
}

var nodeIDs set.Set[ids.NodeID]
for _, validator := range currentValidators {
nodeIDs.Add(validator.NodeID)
}
return nodeIDs, nil
}
34 changes: 34 additions & 0 deletions genesis/validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package genesis

import (
"encoding/json"
"fmt"

_ "embed"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/set"
)

var (
//go:embed validators.json
validatorsPerNetworkJSON []byte

validatorsPerNetwork map[string]set.Set[ids.NodeID]
)

func init() {
if err := json.Unmarshal(validatorsPerNetworkJSON, &validatorsPerNetwork); err != nil {
panic(fmt.Sprintf("failed to decode validators.json: %v", err))
}
}

// GetValidators returns recent validators for the requested network.
func GetValidators(networkID uint32) set.Set[ids.NodeID] {
networkName := constants.NetworkIDToNetworkName[networkID]
return validatorsPerNetwork[networkName]
}
Loading

0 comments on commit 389a4ee

Please sign in to comment.