diff --git a/cmd/da-light-client/update/update.go b/cmd/da-light-client/update/update.go index 987b71b3..f8c07795 100644 --- a/cmd/da-light-client/update/update.go +++ b/cmd/da-light-client/update/update.go @@ -35,7 +35,7 @@ func Cmd() *cobra.Command { } pterm.Info.Println("stopping existing system services, if any...") - err = servicemanager.Start([]string{"da-light-client"}) + err = servicemanager.StartSystemServices([]string{"da-light-client"}) if err != nil { pterm.Error.Println("failed to stop system services: ", err) return diff --git a/cmd/relayer/setup/setup.go b/cmd/relayer/setup/setup.go index ce0e78cf..5f6814cd 100644 --- a/cmd/relayer/setup/setup.go +++ b/cmd/relayer/setup/setup.go @@ -9,11 +9,9 @@ import ( "strings" "time" - "cloud.google.com/go/firestore" firebase "firebase.google.com/go" "github.com/pterm/pterm" "github.com/spf13/cobra" - "google.golang.org/api/iterator" "google.golang.org/api/option" initconfig "github.com/dymensionxyz/roller/cmd/config/init" @@ -25,6 +23,7 @@ import ( dymintutils "github.com/dymensionxyz/roller/utils/dymint" "github.com/dymensionxyz/roller/utils/errorhandling" "github.com/dymensionxyz/roller/utils/filesystem" + firebaseutils "github.com/dymensionxyz/roller/utils/firebase" "github.com/dymensionxyz/roller/utils/genesis" "github.com/dymensionxyz/roller/utils/logging" relayerutils "github.com/dymensionxyz/roller/utils/relayer" @@ -136,38 +135,12 @@ func Cmd() *cobra.Command { // Fetch DRS version information using the nested collection path // Path format: versions/{version}/revisions/{revision} - drsDoc := client.Collection("versions"). - Doc(drsVersion). - Collection("revisions"). - OrderBy("timestamp", firestore.Desc). - Limit(1). - Documents(ctx) - - doc, err := drsDoc.Next() - if err == iterator.Done { - pterm.Error.Printfln("DRS version not found for %s", drsVersion) - return - } + drsInfo, err := firebaseutils.GetLatestDrsVersionCommit(drsVersion) if err != nil { - pterm.Error.Printfln("DRS version not found for %s", drsVersion) - return - } - - var drsInfo dependencies.DrsVersionInfo - if err := doc.DataTo(&drsInfo); err != nil { - pterm.Error.Printfln("DRS version not found for %s", drsVersion) + pterm.Error.Println("failed to retrieve latest DRS version: ", err) return } - dep := dependencies.DefaultRelayerPrebuiltDependencies() - for _, v := range dep { - err := dependencies.InstallBinaryFromRelease(v) - if err != nil { - pterm.Error.Printfln("failed to install binary: %s", err) - return - } - } - rbi := dependencies.NewRollappBinaryInfo( raResp.Rollapp.GenesisInfo.Bech32Prefix, drsInfo.Commit, diff --git a/cmd/rollapp/drs/drs.go b/cmd/rollapp/drs/drs.go new file mode 100644 index 00000000..e68d3d16 --- /dev/null +++ b/cmd/rollapp/drs/drs.go @@ -0,0 +1,18 @@ +package drs + +import ( + "github.com/spf13/cobra" + + "github.com/dymensionxyz/roller/cmd/rollapp/drs/update" +) + +func Cmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "drs", + Short: "Commands related to drs(Dymension RollApp Standard).", + } + + cmd.AddCommand(update.Cmd()) + + return cmd +} diff --git a/cmd/rollapp/drs/update/update.go b/cmd/rollapp/drs/update/update.go new file mode 100644 index 00000000..75cc4586 --- /dev/null +++ b/cmd/rollapp/drs/update/update.go @@ -0,0 +1,142 @@ +package update + +import ( + "os" + "path/filepath" + "strings" + + "github.com/pterm/pterm" + "github.com/spf13/cobra" + + initconfig "github.com/dymensionxyz/roller/cmd/config/init" + "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/utils/archives" + "github.com/dymensionxyz/roller/utils/dependencies" + dymintutils "github.com/dymensionxyz/roller/utils/dymint" + "github.com/dymensionxyz/roller/utils/filesystem" + firebaseutils "github.com/dymensionxyz/roller/utils/firebase" + rollapputils "github.com/dymensionxyz/roller/utils/rollapp" + "github.com/dymensionxyz/roller/utils/roller" + servicemanager "github.com/dymensionxyz/roller/utils/service_manager" +) + +func Cmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "update", + Short: "Update the drs(Dymension RollApp Standard).", + Run: func(cmd *cobra.Command, args []string) { + pterm.Info.Println("preparing update") + home, err := filesystem.ExpandHomePath( + cmd.Flag(initconfig.GlobalFlagNames.Home).Value.String(), + ) + if err != nil { + pterm.Error.Println("failed to expand home directory") + return + } + + rollerData, err := roller.LoadConfig(home) + if err != nil { + pterm.Error.Println("failed to load roller config file", err) + return + } + + cv, err := dependencies.ExtractCommitFromBinaryVersion(consts.Executables.RollappEVM) + if err != nil { + pterm.Error.Println("Failed to get the current commit:", err) + return + } + + drsVersion, err := rollapputils.ExtractDrsVersionFromBinary() + if err != nil { + pterm.Error.Println("Failed to extract drs version from binary:", err) + return + } + + drsInfo, err := firebaseutils.GetLatestDrsVersionCommit(drsVersion) + if err != nil { + pterm.Error.Println("Failed to get the latest commit:", err) + return + } + + if drsInfo.Commit[:6] == cv { + pterm.Info.Println("You are already using the latest version of DRS") + return + } + + // if doesn't match, take latest as the reference + // download the latest, build into ~/.roller/tmp + raResp, err := rollapputils.GetMetadataFromChain( + rollerData.RollappID, + rollerData.HubData, + ) + if err != nil { + pterm.Error.Println("failed to fetch rollapp information from hub: ", err) + return + } + + raNewBinDir, err := os.MkdirTemp(os.TempDir(), "rollapp-drs-update") + if err != nil { + pterm.Error.Println( + "failed to create temporary directory for rollapp binary: ", + err, + ) + return + } + defer os.RemoveAll(raNewBinDir) + + rbi := dependencies.NewRollappBinaryInfo( + raResp.Rollapp.GenesisInfo.Bech32Prefix, + drsInfo.Commit, + strings.ToLower(raResp.Rollapp.VmType), + ) + + raDep := dependencies.DefaultRollappDependency(rbi) + // override the binary destination with the previously created tmp directory + // as the binary will be copied to the final destination after stopping the + // system services + tmpBinLocation := filepath.Join( + raNewBinDir, + "rollappd", + ) + + pterm.Info.Println("starting update") + raDep.Binaries[0].BinaryDestination = tmpBinLocation + err = dependencies.InstallBinaryFromRepo(raDep, raDep.DependencyName) + if err != nil { + pterm.Error.Println("failed to install rollapp binary: ", err) + return + } + + // stop services + err = servicemanager.StopSystemServices([]string{"rollapp"}) + if err != nil { + pterm.Error.Println("failed to stop rollapp services: ", err) + return + } + + // repalce the current binary with the new one + err = archives.MoveBinaryIntoPlaceAndMakeExecutable( + tmpBinLocation, + consts.Executables.RollappEVM, + ) + if err != nil { + pterm.Error.Println("failed to move rollapp binary: ", err) + return + } + + // start services + err = servicemanager.StartSystemServices([]string{"rollapp"}) + if err != nil { + pterm.Error.Println("failed to stop rollapp services: ", err) + return + } + + // wait for healthy endpoint + dymintutils.WaitForHealthyRollApp("http://localhost:26657/health") + + pterm.Success.Println("update complete") + }, + } + + return cmd +} diff --git a/cmd/rollapp/rollapp.go b/cmd/rollapp/rollapp.go index 5bc1c81e..53d67080 100644 --- a/cmd/rollapp/rollapp.go +++ b/cmd/rollapp/rollapp.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/dymensionxyz/roller/cmd/rollapp/config" + "github.com/dymensionxyz/roller/cmd/rollapp/drs" initrollapp "github.com/dymensionxyz/roller/cmd/rollapp/init" "github.com/dymensionxyz/roller/cmd/rollapp/keys" "github.com/dymensionxyz/roller/cmd/rollapp/migrate" @@ -32,6 +33,7 @@ func Cmd() *cobra.Command { cmd.AddCommand(sequencer.Cmd()) cmd.AddCommand(keys.Cmd()) cmd.AddCommand(migrate.Cmd()) + cmd.AddCommand(drs.Cmd()) sl := []string{"rollapp", "da-light-client"} cmd.AddCommand( diff --git a/utils/archives/archives.go b/utils/archives/archives.go index c843cbd8..d637d93c 100644 --- a/utils/archives/archives.go +++ b/utils/archives/archives.go @@ -55,18 +55,8 @@ func ExtractTarGz(path string, data io.ReadCloser, dep dependencytypes.Dependenc } for _, bin := range dep.Binaries { - err := bash.ExecCommandWithInteractions( - "sudo", - "mv", - filepath.Join(path, bin.Binary), - bin.BinaryDestination, - ) - if err != nil { - return err - } - err = bash.ExecCommandWithInteractions( - "sudo", - "chmod", "+x", + err := MoveBinaryIntoPlaceAndMakeExecutable( + path, bin.BinaryDestination, ) if err != nil { @@ -76,3 +66,27 @@ func ExtractTarGz(path string, data io.ReadCloser, dep dependencytypes.Dependenc return err } + +// MoveBinaryIntoPlaceAndMakeExecutable is a fantastic function name, ik +func MoveBinaryIntoPlaceAndMakeExecutable( + src, dest string, +) error { + err := bash.ExecCommandWithInteractions( + "sudo", + "mv", + src, + dest, + ) + if err != nil { + return err + } + err = bash.ExecCommandWithInteractions( + "sudo", + "chmod", "+x", + dest, + ) + if err != nil { + return err + } + return nil +} diff --git a/utils/dependencies/dependencies.go b/utils/dependencies/dependencies.go index 3ba908d8..b88ba375 100644 --- a/utils/dependencies/dependencies.go +++ b/utils/dependencies/dependencies.go @@ -1,7 +1,6 @@ package dependencies import ( - "context" "errors" "fmt" "io" @@ -13,28 +12,20 @@ import ( "strconv" "strings" - "cloud.google.com/go/firestore" - firebase "firebase.google.com/go" "github.com/pterm/pterm" "github.com/schollz/progressbar/v3" "golang.org/x/text/cases" "golang.org/x/text/language" - "google.golang.org/api/iterator" - "google.golang.org/api/option" "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/utils/archives" "github.com/dymensionxyz/roller/utils/bash" "github.com/dymensionxyz/roller/utils/dependencies/types" + firebaseutils "github.com/dymensionxyz/roller/utils/firebase" genesisutils "github.com/dymensionxyz/roller/utils/genesis" "github.com/dymensionxyz/roller/utils/rollapp" ) -// DrsVersionInfo represents the structure of DRS version information in Firestore -type DrsVersionInfo struct { - Commit string `firestore:"commit"` -} - func InstallBinaries(withMockDA bool, raResp rollapp.ShowRollappResponse) ( map[string]types.Dependency, map[string]types.Dependency, @@ -54,7 +45,7 @@ func InstallBinaries(withMockDA bool, raResp rollapp.ShowRollappResponse) ( // nolint: errcheck defer os.RemoveAll(genesisTmpDir) - var raBinCommit string + var drsVersion string raVmType := strings.ToLower(raResp.Rollapp.VmType) if !withMockDA { // TODO refactor, this genesis file fetch is redundand and will slow the process down @@ -74,48 +65,13 @@ func InstallBinaries(withMockDA bool, raResp rollapp.ShowRollappResponse) ( return nil, nil, err } - raBinCommit = strconv.Itoa(as.RollappParams.Params.DrsVersion) - pterm.Info.Println("RollApp binary version from the genesis file : ", raBinCommit) - - // TODO: extract to helper - // Initialize Firestore client - ctx := context.Background() - conf := &firebase.Config{ProjectID: "drs-metadata"} - app, err := firebase.NewApp(ctx, conf, option.WithoutAuthentication()) + drsVersion = strconv.Itoa(as.RollappParams.Params.DrsVersion) + pterm.Info.Println("RollApp binary version from the genesis file : ", drsVersion) + drsInfo, err := firebaseutils.GetLatestDrsVersionCommit(drsVersion) if err != nil { - return nil, nil, fmt.Errorf("failed to initialize firebase app: %v", err) - } - - client, err := app.Firestore(ctx) - if err != nil { - return nil, nil, fmt.Errorf("failed to create firestore client: %v", err) - } - defer client.Close() - - // Fetch DRS version information using the nested collection path - // Path format: versions/{version}/revisions/{revision} - drsDoc := client.Collection("versions"). - Doc(raBinCommit). - Collection("revisions"). - OrderBy("timestamp", firestore.Desc). - Limit(1). - Documents(ctx) - - doc, err := drsDoc.Next() - if err == iterator.Done { return nil, nil, err } - if err != nil { - return nil, nil, err - } - - var drsInfo DrsVersionInfo - if err := doc.DataTo(&drsInfo); err != nil { - return nil, nil, fmt.Errorf("failed to parse DRS version info: %v", err) - } - - pterm.Info.Printf("Found DRS commit hash: %s\n", drsInfo.Commit) - raBinCommit = drsInfo.Commit + drsVersion = drsInfo.Commit } defer func() { @@ -131,7 +87,7 @@ func InstallBinaries(withMockDA bool, raResp rollapp.ShowRollappResponse) ( if !withMockDA { rbi := NewRollappBinaryInfo( raResp.Rollapp.GenesisInfo.Bech32Prefix, - raBinCommit, + drsVersion, raVmType, ) diff --git a/utils/firebase/firebase.go b/utils/firebase/firebase.go new file mode 100644 index 00000000..162e8f13 --- /dev/null +++ b/utils/firebase/firebase.go @@ -0,0 +1,57 @@ +package firebase + +import ( + "context" + "fmt" + + "cloud.google.com/go/firestore" + firebase "firebase.google.com/go" + "github.com/pterm/pterm" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +// DrsVersionInfo represents the structure of DRS version information in Firestore +type DrsVersionInfo struct { + Commit string `firestore:"commit"` +} + +func GetLatestDrsVersionCommit(drsVersion string) (*DrsVersionInfo, error) { + ctx := context.Background() + conf := &firebase.Config{ProjectID: "drs-metadata"} + app, err := firebase.NewApp(ctx, conf, option.WithoutAuthentication()) + if err != nil { + return nil, fmt.Errorf("failed to initialize firebase app: %v", err) + } + + client, err := app.Firestore(ctx) + if err != nil { + return nil, fmt.Errorf("failed to create firestore client: %v", err) + } + defer client.Close() + + // Fetch DRS version information using the nested collection path + // Path format: versions/{version}/revisions/{revision} + drsDoc := client.Collection("versions"). + Doc(drsVersion). + Collection("revisions"). + OrderBy("timestamp", firestore.Desc). + Limit(1). + Documents(ctx) + + doc, err := drsDoc.Next() + if err == iterator.Done { + return nil, err + } + if err != nil { + return nil, err + } + + var drsInfo DrsVersionInfo + if err := doc.DataTo(&drsInfo); err != nil { + return nil, fmt.Errorf("failed to parse DRS version info: %v", err) + } + + pterm.Info.Printf("Found DRS commit hash: %s\n", drsInfo.Commit) + return &drsInfo, nil +} diff --git a/utils/rollapp/bechprefix.go b/utils/rollapp/bechprefix.go index 27137abf..82736017 100644 --- a/utils/rollapp/bechprefix.go +++ b/utils/rollapp/bechprefix.go @@ -55,3 +55,43 @@ func ExtractBech32PrefixFromBinary(vmType string) (string, error) { return bech32Prefix, err } + +func ExtractDrsVersionFromBinary() (string, error) { + pterm.Info.Println("extracting drs version") + c := exec.Command( + "go", + "version", + "-m", + consts.Executables.RollappEVM, + ) + + out, err := bash.ExecCommandWithStdout(c) + if err != nil { + return "", err + } + + lines := strings.Split(out.String(), "\n") + pattern := `github\.com/dymensionxyz/dymint/version\.DrsVersion=(\w+)` + + re := regexp.MustCompile(pattern) + var ldflags string + var drsVersion string + + for _, line := range lines { + if strings.Contains(line, "-ldflags") { + // Print the line containing "-ldflags" + ldflags = line + break + } + } + + match := re.FindStringSubmatch(ldflags) + if len(match) > 1 { + // Print the captured value + drsVersion = match[1] + } else { + return "", errors.New("rollapp binary does not contain build flags ") + } + + return drsVersion, err +} diff --git a/utils/sequencer/sequencer.go b/utils/sequencer/sequencer.go index f3d9d5c7..d6f1355f 100644 --- a/utils/sequencer/sequencer.go +++ b/utils/sequencer/sequencer.go @@ -49,7 +49,6 @@ func Register(raCfg roller.RollappConfig, desiredBond cosmossdktypes.Coin) error ).Show() customRewardAddress = strings.TrimSpace(customRewardAddress) - // TODO: improve ux args := []string{ "tx", "sequencer", diff --git a/utils/service_manager/service.go b/utils/service_manager/service.go index c3ecbecf..43ca5d2f 100644 --- a/utils/service_manager/service.go +++ b/utils/service_manager/service.go @@ -122,7 +122,7 @@ func (s *ServiceConfig) RunServiceWithRestart(name string, options ...bash.Comma }() } -func Start(services []string) error { +func StartSystemServices(services []string) error { pterm.Info.Println("starting existing system services, if any...") switch runtime.GOOS { case "linux":