Skip to content

Commit

Permalink
Initial support for installing Firedancer/Frankendancer
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderguy committed Dec 5, 2024
1 parent 26a94e2 commit 4a3fea2
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 0 deletions.
14 changes: 14 additions & 0 deletions pkg/firedancer/assets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package firedancer

import (
"embed"
)

//go:embed assets
var assets embed.FS

const (
assetsInstall = "assets/install"
assetsFDService = "assets/svmkit-fd.service"
assetsFDSetupService = "assets/svmkit-fd-setup.service"
)
59 changes: 59 additions & 0 deletions pkg/firedancer/assets/install
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# -*- mode: shell-script -*-
# shellcheck shell=bash

USER=sol
GROUP=sol
HOME=/home/$USER

VALIDATOR_PACKAGE=svmkit-frankendancer
VALIDATOR_SERVICE=${VALIDATOR_PACKAGE}.service

step::00::wait-for-a-stable-environment() {
cloud-init::wait-for-stable-environment
}

step::05::setup-abklabs-apt() {
apt::setup-abk-apt-source
}

step::20::create-sol-user() {
create-sol-user
}

step::30::copy-assets() {
$SUDO cp validator-keypair.json vote-account-keypair.json config.toml "$HOME"
$SUDO chown "$USER:$GROUP" "$HOME"/{validator-keypair,vote-account-keypair}.json "$HOME"/config.toml

$SUDO cp *.service /etc/systemd/system/.
$SUDO systemctl daemon-reload
}

step::70::install-validator() {
if [[ -v VALIDATOR_VERSION ]]; then
# XXX - This needs to be fixed up to be able to select the right solana CLI major version.
$APT --allow-downgrades install "${VALIDATOR_PACKAGE}=$VALIDATOR_VERSION" "svmkit-solana-cli"
else
$APT --allow-downgrades install "${VALIDATOR_PACKAGE}" "svmkit-solana-cli"
fi
}

step::75::setup-solana-cli() {
[[ -v SOLANA_CLI_CONFIG_FLAGS ]] || return 0

# First setup the login user.
solana config set $SOLANA_CLI_CONFIG_FLAGS

# Setup the sol user.
$SUDO -u "$USER" -i solana config set $SOLANA_CLI_CONFIG_FLAGS
}

step::80::setup-validator() {
if systemctl list-unit-files svmkit-fd.service >/dev/null; then
$SUDO systemctl stop svmkit-fd.service || true
fi

$SUDO systemctl enable svmkit-fd-setup.service
$SUDO systemctl start svmkit-fd-setup.service
$SUDO systemctl enable svmkit-fd-validator.service
$SUDO systemctl start svmkit-fd-validator.service
}
15 changes: 15 additions & 0 deletions pkg/firedancer/assets/svmkit-fd-setup.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=SVMkit FD Machine Setup
After=local-fs.target
After=network.target

[Service]
Type=exec
User=root
Group=root
ExecStart=/opt/frankendancer/bin/fdctl --config /home/sol/config.toml configure init all
RemainAfterExit=true
Type=oneshot

[Install]
WantedBy=default.target
13 changes: 13 additions & 0 deletions pkg/firedancer/assets/svmkit-fd.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=SVMkit FD Validator
After=svmkit-fd-setup.service
Requires=svmkit-fd-setup.service

[Service]
Type=exec
User=root
Group=root
ExecStart=/opt/frankendancer/bin/fdctl --config /home/sol/config.toml run

[Install]
WantedBy=default.target
126 changes: 126 additions & 0 deletions pkg/firedancer/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package firedancer

import (
"github.com/BurntSushi/toml"
"io"
)

type ConfigLog struct {
Path *string `toml:"path,omitempty" pulumi:"path,optional"`
Colorize *string `toml:"colorize,omitempty" pulumi:"colorize,optional"`
LevelLogfile *string `toml:"level_logfile,omitempty" pulumi:"levelLogfile,optional"`
LevelStderr *string `toml:"level_stderr,omitempty" pulumi:"levelStderr,optional"`
LevelFlush *string `toml:"level_flush,omitempty" pulumi:"levelFlush,optional"`
}

type ConfigReporting struct {
SolanaMetricsConfig *string `toml:"solana_metrics_config,omitempty" pulumi:"solanaMetricsConfig,optional"`
}

type ConfigLedger struct {
Path *string `toml:"path,omitempty" pulumi:"path,optional"`
AccountsPath *string `toml:"accounts_path,omitempty" pulumi:"accountsPath,optional"`
LimitSize *int `toml:"limit_size,omitempty" pulumi:"limitSize,optional"`
AccountIndexes *[]string `toml:"account_indexes,omitempty" pulumi:"accountIndexes,optional"`
AccountIndexExcludeKeys *[]string `toml:"account_index_exclude_keys,omitempty" pulumi:"accountIndexExcludeKeys,optional"`
AccountIndexIncludeKeys *[]string `toml:"account_index_include_keys,omitempty" pulumi:"accountIndexIncludeKeys,optional"`
SnapshotArchiveFormat *string `toml:"snapshot_archive_format,omitempty" pulumi:"snapshotArchiveFormat,optional"`
RequireTower *bool `toml:"require_tower,omitempty" pulumi:"requireTower,optional"`
}

type ConfigGossip struct {
Entrypoints *[]string `toml:"entrypoints,omitempty" pulumi:"entrypoints,optional"`
PortCheck *bool `toml:"port_check,omitempty" pulumi:"portCheck,optional"`
Port *int `toml:"port,omitempty" pulumi:"port,optional"`
Host *string `toml:"host,omitempty" pulumi:"host,optional"`
}

type ConfigRPC struct {
Port *int `toml:"port,omitempty" pulumi:"port,optional"`
FullAPI *bool `toml:"full_api,omitempty" pulumi:"fullApi,optional"`
Private *bool `toml:"private,omitempty" pulumi:"private,optional"`
TransactionHistory *bool `toml:"transaction_history,omitempty" pulumi:"transactionHistory,optional"`
ExtendedTxMetadataStorage *bool `toml:"extended_tx_metadata_storage,omitempty" pulumi:"extendedTxMetadataStorage,optional"`
OnlyKnown *bool `toml:"only_known,omitempty" pulumi:"onlyKnown,optional"`
PubsubEnableBlockSubscription *bool `toml:"pubsub_enable_block_subscription,omitempty" pulumi:"pubsubEnableBlockSubscription,optional"`
PubsubEnableVoteSubscription *bool `toml:"pubsub_enable_vote_subscription,omitempty" pulumi:"pubsubEnableVoteSubscription,optional"`
BigtableLedgerStorage *bool `toml:"bigtable_ledger_storage,omitempty" pulumi:"bigtableLedgerStorage,optional"`
}

type ConfigSnapshots struct {
IncrementalSnapshots *bool `toml:"incremental_snapshots,omitempty" pulumi:"incrementalSnapshots,optional"`
FullSnapshotIntervalSlots *int `toml:"full_snapshot_interval_slots,omitempty" pulumi:"fullSnapshotIntervalSlots,optional"`
IncrementalSnapshotIntervalSlots *int `toml:"incremental_snapshot_interval_slots,omitempty" pulumi:"incrementalSnapshotIntervalSlots,optional"`
MaximumFullSnapshotsToRetain *int `toml:"maximum_full_snapshots_to_retain,omitempty" pulumi:"maximumFullSnapshotsToRetain,optional"`
MaximumIncrementalSnapshotsToRetain *int `toml:"maximum_incremental_snapshots_to_retain,omitempty" pulumi:"maximumIncrementalSnapshotsToRetain,optional"`
MinimumSnapshotDownloadSpeed *int `toml:"minimum_snapshot_download_speed,omitempty" pulumi:"minimumSnapshotDownloadSpeed,optional"`
Path *string `toml:"path,omitempty" pulumi:"path,optional"`
IncrementalPath *string `toml:"incremental_path,omitempty" pulumi:"incrementalPath,optional"`
}

type ConfigConsensus struct {
IdentityPath *string `toml:"identity_path,omitempty" pulumi:"identityPath,optional"`
VoteAccountPath *string `toml:"vote_account_path,omitempty" pulumi:"voteAccountPath,optional"`
AuthorizedVoterPaths *[]string `toml:"authorized_voter_paths,omitempty" pulumi:"authorizedVoterPaths,optional"`
SnapshotFetch *bool `toml:"snapshot_fetch,omitempty" pulumi:"snapshotFetch,optional"`
GenesisFetch *bool `toml:"genesis_fetch,omitempty" pulumi:"genesisFetch,optional"`
PohSpeedTest *bool `toml:"poh_speed_test,omitempty" pulumi:"pohSpeedTest,optional"`
ExpectedGenesisHash *string `toml:"expected_genesis_hash,omitempty" pulumi:"expectedGenesisHash,optional"`
WaitForSupermajorityAtSlot *int `toml:"wait_for_supermajority_at_slot,omitempty" pulumi:"waitForSupermajorityAtSlot,optional"`
ExpectedBankHash *string `toml:"expected_bank_hash,omitempty" pulumi:"expectedBankHash,optional"`
ExpectedShredVersion *int `toml:"expected_shred_version,omitempty" pulumi:"expectedShredVersion,optional"`
WaitForVoteToStartLeader *bool `toml:"wait_for_vote_to_start_leader,omitempty" pulumi:"waitForVoteToStartLeader,optional"`
OsNetworkLimitsTest *bool `toml:"os_network_limits_test,omitempty" pulumi:"osNetworkLimitsTest,optional"`
HardForkAtSlots *[]string `toml:"hard_fork_at_slots,omitempty" pulumi:"hardForkAtSlots,optional"`
KnownValidators *[]string `toml:"known_validators,omitempty" pulumi:"knownValidators,optional"`
}

type ConfigLayout struct {
Affinity *string `toml:"affinity,omitempty" pulumi:"affinity,optional"`
AgaveAffinity *string `toml:"agave_affinity,omitempty" pulumi:"agaveAffinity,optional"`
NetTileCount *int `toml:"net_tile_count,omitempty" pulumi:"netTileCount,optional"`
QuicTileCount *int `toml:"quic_tile_count,omitempty" pulumi:"quicTileCount,optional"`
ResolvTileCount *int `toml:"resolv_tile_count,omitempty" pulumi:"resolvTileCount,optional"`
VerifyTileCount *int `toml:"verify_tile_count,omitempty" pulumi:"verifyTileCount,optional"`
BankTileCount *int `toml:"bank_tile_count,omitempty" pulumi:"bankTileCount,optional"`
ShredTileCount *int `toml:"shred_tile_count,omitempty" pulumi:"shredTileCount,optional"`
}

type ConfigHugeTLBFS struct {
MountPath *string `toml:"mount_path,omitempty" pulumi:"mountPath,optional"`
}

type Config struct {
Name *string `toml:"name,omitempty" pulumi:"name,optional"`
User *string `toml:"user,omitempty" pulumi:"user,optional"`
ScratchDirectory *string `toml:"scratch_directory,omitempty" pulumi:"scratchDirectory,optional"`
DynamicPortRange *string `toml:"dynamic_port_range,omitempty" pulumi:"dynamicPortRange,optional"`

Log *ConfigLog `toml:"log,omitempty" pulumi:"log,optional"`
Reporting *ConfigReporting `toml:"reporting,omitempty" pulumi:"reporting,optional"`
Ledger *ConfigLedger `toml:"ledger,omitempty" pulumi:"ledger,optional"`
Gossip *ConfigGossip `toml:"gossip,omitempty" pulumi:"gossip,optional"`
RPC *ConfigRPC `toml:"rpc,omitempty" pulumi:"rpc,optional"`
Snapshots *ConfigSnapshots `toml:"snapshots,omitempty" pulumi:"snapshots,optional"`
Consensus *ConfigConsensus `toml:"consensus,omitempty" pulumi:"consensus,optional"`
Layout *ConfigLayout `toml:"layout,omitempty" pulumi:"layout,optional"`
HugeTLBFS *ConfigHugeTLBFS `toml:"hugetlbfs,omitempty" pulumi:"hugetlbfs,optional"`

ExtraConfig *[]string `pulumi:"extraConfig,optional"`
}

func (c *Config) Encode(w io.Writer) error {
if err := toml.NewEncoder(w).Encode(c); err != nil {
return err
}

if c.ExtraConfig != nil {
for _, v := range *c.ExtraConfig {
if _, err := w.Write([]byte(v)); err != nil {
return err
}
}
}

return nil
}
79 changes: 79 additions & 0 deletions pkg/firedancer/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package firedancer

import (
"github.com/abklabs/svmkit/pkg/runner"
)

type KeyPairs struct {
Identity string `pulumi:"identity" provider:"secret"`
VoteAccount string `pulumi:"voteAccount" provider:"secret"`
}

type Firedancer struct {
KeyPairs KeyPairs `pulumi:"keyPairs"`
Config Config `pulumi:"config"`
}

func (fd *Firedancer) Install() runner.Command {
return &InstallCommand{
Firedancer: *fd,
}
}

type InstallCommand struct {
Firedancer
}

func (c *InstallCommand) Check() error {
return nil
}

func (c *InstallCommand) Env() *runner.EnvBuilder {
e := runner.NewEnvBuilder()
return e
}

func (c *InstallCommand) AddToPayload(p *runner.Payload) error {
{
w := p.NewWriter(runner.PayloadFile{Path: "config.toml"})

if err := c.Config.Encode(w); err != nil {
return err
}
}

{
r, err := assets.Open(assetsInstall)

if err != nil {
return err
}

p.AddReader("steps.sh", r)
}

{
r, err := assets.Open(assetsFDService)

if err != nil {
return err
}

p.AddReader("svmkit-fd-validator.service", r)
}

{
r, err := assets.Open(assetsFDSetupService)

if err != nil {
return err
}

p.AddReader("svmkit-fd-setup.service", r)
}

p.AddString("validator-keypair.json", c.KeyPairs.Identity)
p.AddString("vote-account-keypair.json", c.KeyPairs.VoteAccount)

return nil
}
27 changes: 27 additions & 0 deletions pkg/firedancer/variant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package firedancer

import (
"github.com/pulumi/pulumi-go-provider/infer"
)

type Variant string

const (
VariantFrankendancer Variant = "frankendancer"
VariantFiredancer Variant = "firedancer"
)

func (Variant) Values() []infer.EnumValue[Variant] {
return []infer.EnumValue[Variant]{
{
Name: string(VariantFrankendancer),
Value: VariantFrankendancer,
Description: "The Frankendancer variant",
},
{
Name: string(VariantFiredancer),
Value: VariantFiredancer,
Description: "The Firedancer variant",
},
}
}

0 comments on commit 4a3fea2

Please sign in to comment.