diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64fdc22a..de30e1ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: - name: Build Server shell: bash - run: task build:server + run: task build env: OS: ${{ matrix.target }} ARCH: ${{ matrix.arch }} diff --git a/README.md b/README.md index e56ceb9e..a1dc968b 100644 --- a/README.md +++ b/README.md @@ -6,154 +6,5 @@ DeWeb is your gateway to the decentralized web, enabling seamless access to webs DeWeb revolutionizes web accessibility by providing tools to upload, edit, and view websites directly on the blockchain. The project includes two binaries: -- `deweb-cli`: A command-line tool for deploying and managing on-chain websites. -- `deweb-server`: A server application that allows users to access websites stored on-chain through a web browser. - -## Getting Started - -### Prerequisites - -Ensure you have `task` installed. Follow the instructions [here](https://taskfile.dev/installation/). - -### Installation - -1. Navigate to server folder: - - ```bash - cd server - ``` - -2. Install required tools: - - ```bash - task install - ``` - -3. Generate: - - ```bash - task generate - ``` - -4. Build both binaries: - - ```bash - task build - ``` - - Alternatively, you can build them separately: - - ```bash - task build:cli - task build:server - ``` - -5. The binaries will be stored in the `./build` directory. - -# DeWeb CLI - -DeWeb CLI is a command-line tool designed for deploying, editing, and deleting decentralized websites on the DeWeb platform. - -## Usage - -Once installed, you can use the `deweb-cli` command to interact with DeWeb. Below is the basic usage syntax: - -```bash -deweb-cli [global options] command [command options] [arguments...] -``` - -### Global Options - -- `--wallet_nickname, -w`: Specify the wallet nickname to use. -- `--node_url, -n`: Specify the node URL. -- `--config, -c`: Load configuration from a specified file path (default: `./deweb_cli_config.yaml`). - -## Commands - -### upload - -Uploads a new website to the DeWeb platform. - -```bash -deweb-cli upload [global options] -``` - -#### Arguments - -- ``: Path to the zip file containing the website to be uploaded. - -#### Example - -```bash -deweb-cli upload -w myWallet -n https://mainnet.massa.net/api/v2 ./website.zip -``` - -The zip file should contain an `index.html` at its root. For example, if you build an app and the output is in a directory (usually `build` or `dist`), you can zip it using the following command from the output directory: - -```bash -zip {name}.zip -r ./* -``` - -This should result in a zip file with all the files from the output directory, with the `index.html` at its root. - -> Note: Server Side Rendering (SSR) is not supported at this time. Ensure your website is fully client-side rendered. - -### edit - -Edits an existing website on the DeWeb platform. - -```bash -deweb-cli edit [global options] -``` - -#### Arguments - -- ``: Smart contract address of the website to be edited. -- ``: Path to the zip file containing the updated website. - -#### Example - -```bash -deweb-cli edit -w myWallet -n http://node-url.com ./updated_website.zip -``` - -### delete - -Deletes an existing website from the DeWeb platform. - -```bash -deweb-cli delete [global options] -``` - -#### Arguments - -- ``: Smart contract address of the website to be deleted. - -#### Example - -```bash -deweb-cli delete -w myWallet -n http://node-url.com -``` - -## Configuration - -The CLI can be configured using a YAML file. By default, it looks for `deweb_cli_config.yaml` in the current directory. You can specify a different configuration file using the `--config` flag. - -### Sample Configuration (`deweb_cli_config.yaml`) - -```yaml -wallet_config: - wallet_nickname: "alice" - -node_url: "https://buildnet.massa.net/api/v2" - -sc_config: - minimal_fees: 0 - max_gas: 0 - max_coins: 0 - expiry: 0 -``` - -## Logging - -The CLI logs its output to `./deweb-cli.log`. Logging is initialized automatically when the application starts. +- [`deweb-cli`](./cli/README.md): A command-line tool for deploying and managing on-chain websites. +- [`deweb-server`](./server/README.md): A server application that allows users to access websites stored on-chain through a web browser. diff --git a/cli/README.md b/cli/README.md index b4b57be4..c5e91787 100644 --- a/cli/README.md +++ b/cli/README.md @@ -3,3 +3,47 @@ DeWeb CLI is a command-line tool designed for developers to manage website deployments on the Massa blockchain. It provides commands for uploading, managing, and debugging website files directly on the blockchain, simplifying the deployment process. For more information about the DeWeb CLI, how to use it, and how to upload a website to the Massa blockchain, see the [DeWeb CLI documentation](https://docs.massa.net/docs/deweb/cli/overview). + +## Getting Started + +### Prerequisites + +To use and work on the DeWeb CLI, you need to have the following tools installed: + +- **Node.js** (version 18.0 or higher) and **npm** installed. You can check your versions with: + + ```bash + node -v + npm -v + ``` + + If you don't have Node.js installed, you can download it from the [official website](https://nodejs.org/). + +- A **Massa account**. If you don't have one, you can create one using the Massa Wallet available as a plugin of [Massa Station](https://station.massa.net/). You can follow the instructions in the [Massa Wallet documentation](https://docs.massa.net/docs/massaStation/massa-wallet/getting-started) to install the wallet and create an account. + +### Installation + +1. Install dependencies: + + ```bash + npm install + ``` + +2. Build the CLI: + + ```bash + npm run build + ``` + +3. The CLI will be stored in the `./bin` directory and can be run using: + ```bash + npm run start + ``` + +### Run in development mode + +To run the CLI in development mode, you can use: + +```bash +npm run dev +``` diff --git a/server/README.md b/server/README.md new file mode 100644 index 00000000..74c66df4 --- /dev/null +++ b/server/README.md @@ -0,0 +1,35 @@ +# DeWeb Server + +DeWeb Server allows users to access websites stored on-chain through a web browser. It is also used by providers to allow any user from any platform to access the websites they have uploaded on-chain. + +## Getting Started + +### Prerequisites + +Ensure you have `task` installed. Follow the instructions [here](https://taskfile.dev/installation/). + +### Installation + +1. Install required tools: + + ```bash + task install + ``` + +2. Generate: + + ```bash + task generate + ``` + +3. Build the server binary: + + ```bash + task build + ``` + +4. The binary will be stored in the `./build` directory. + +## Usage + +You can find the usage instructions for DeWeb Server in the [DeWeb Server documentation](https://docs.massa.net/docs/deweb/local-server-config/server-config). diff --git a/server/Taskfile.yml b/server/Taskfile.yml index c55520de..b8e13ce2 100644 --- a/server/Taskfile.yml +++ b/server/Taskfile.yml @@ -14,10 +14,16 @@ tasks: - cmd: cmd /C 'for %f in (pages\*.zip) do move %f int\api\resources\' platforms: [windows] + run: + cmds: + - cmd: ./build/deweb-server + build: cmds: - - task: build:server - - task: build:cli + - task: build:internal + vars: + APP_NAME: server + BIN_DIR: build build:internal: build: @@ -42,28 +48,6 @@ tasks: PRODUCTION: '{{.PRODUCTION | default "false"}}' VERSION: "{{.VERSION | default nil}}" - build:server: - cmds: - - task: build:internal - vars: - APP_NAME: server - BIN_DIR: build - - build:cli: - cmds: - - task: build:internal - vars: - APP_NAME: cli - BIN_DIR: build - - run:cli: - cmds: - - cmd: ./build/deweb-cli - - run:server: - cmds: - - cmd: ./build/deweb-server - clean: cmds: - cmd: rm -rf build diff --git a/server/cmd/cli/main.go b/server/cmd/cli/main.go deleted file mode 100644 index 65425d2b..00000000 --- a/server/cmd/cli/main.go +++ /dev/null @@ -1,391 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "time" - - yamlConfig "github.com/massalabs/deweb-server/int/cli" - "github.com/massalabs/deweb-server/int/config" - "github.com/massalabs/deweb-server/int/utils" - "github.com/massalabs/deweb-server/int/zipper" - pkgConfig "github.com/massalabs/deweb-server/pkg/config" - "github.com/massalabs/deweb-server/pkg/website" - msConfig "github.com/massalabs/station/int/config" - "github.com/massalabs/station/pkg/logger" - "github.com/massalabs/station/pkg/node" - "github.com/urfave/cli/v2" -) - -const ( - defaultYamlConfigPath = "./deweb_cli_config.yaml" - finalityTimeout = 60 * time.Second - finalityTickerInterval = 4 * time.Second -) - -func main() { - var nickname string - - var nodeURL string - - var configPath string - - flags := []cli.Flag{ - &cli.StringFlag{ - Name: "wallet_nickname", - Usage: "selected wallet `wallet_nickname`", - Aliases: []string{"w"}, - Destination: &nickname, - }, - &cli.StringFlag{ - Name: "node_url", - Usage: "selected wallet `node_url`", - Aliases: []string{"n"}, - Destination: &nodeURL, - }, - &cli.StringFlag{ - Name: "config", - Aliases: []string{"c"}, - Usage: "Load configuration from `file_path`", - Value: defaultYamlConfigPath, - DefaultText: defaultYamlConfigPath, - Destination: &configPath, - }, - } - - app := &cli.App{ - Name: "DeWeb CLI", - Usage: "CLI app for deploying websites", - UsageText: "Upload, delete & edit DeWeb site from the terminal", - Version: config.Version, - Flags: flags, - Action: func(cCtx *cli.Context) error { - err := cli.ShowAppHelp(cCtx) - if err != nil { - return fmt.Errorf("failed to show app help: %v", err) - } - return nil - }, - - Commands: []*cli.Command{ - { - Name: "upload", - Aliases: []string{"u"}, - Usage: "Upload a website", - ArgsUsage: "", - Flags: flags, - Action: func(cCtx *cli.Context) error { - if cCtx.Args().Len() < 1 { - return fmt.Errorf("invalid number of arguments\nUsage: %s %s", cCtx.App.Name, cCtx.Command.ArgsUsage) - } - - config, err := yamlConfig.LoadConfig(configPath, nodeURL, nickname) - if err != nil { - return fmt.Errorf("failed to load yaml config: %v", err) - } - - filepath := cCtx.Args().Get(0) - isFilePresent, err := zipper.VerifyFilePresence(filepath, "index.html") - if !isFilePresent { - return fmt.Errorf("invalid zip file: %v", err) - } - - siteAddress, err := deployWebsite(config, filepath) - if err != nil { - logger.Fatalf("failed to deploy website: %v", err) - } - - isFinal, err := waitForUploadFinality(config.NetworkConfig, siteAddress) - if err != nil { - logger.Errorf("failed while waiting for finality: %v\n", err) - } else if !isFinal { - logger.Warnf("upload did not finalize within the given time for addess %s.", siteAddress) - } - - logger.Infof("successfully uploaded a website at %s", siteAddress) - - return nil - }, - }, - { - Name: "edit", - Aliases: []string{"e"}, - Usage: "Edit website", - ArgsUsage: " ", - Flags: flags, - Action: func(cCtx *cli.Context) error { - if cCtx.Args().Len() < 2 { - return fmt.Errorf("invalid number of arguments\nUsage: %s %s", cCtx.App.Name, cCtx.Command.ArgsUsage) - } - - config, err := yamlConfig.LoadConfig(configPath, nodeURL, nickname) - if err != nil { - return fmt.Errorf("failed to load yaml config: %v", err) - } - - siteAddress := cCtx.Args().Get(0) - filepath := cCtx.Args().Get(1) - - isFilePresent, err := zipper.VerifyFilePresence(filepath, "index.html") - if !isFilePresent { - return fmt.Errorf("invalid zip file: %v", err) - } - - bytecode, err := processFileForUpload(filepath) - if err != nil { - logger.Fatalf("failed to process file for upload: %v", err) - } - - err = deleteIfRequired(config, siteAddress, len(bytecode)) - if err != nil { - logger.Errorf("failed to check if delete is required: %v", err) - logger.Warnf("continuing with edit operation for website %s", siteAddress) - } - - err = uploadChunks(bytecode, siteAddress, config) - if err != nil { - logger.Fatalf("failed to upload chunks: %v", err) - } - - isFinal, err := waitForUploadFinality(config.NetworkConfig, siteAddress) - if err != nil { - logger.Errorf("failed while waiting for finality: %v\n", err) - } else if !isFinal { - logger.Warnf("upload did not finalize within the given time for addess %s.", siteAddress) - } - - logger.Infof("successfully uploaded a website at %s", siteAddress) - - return nil - }, - }, - { - Name: "view", - Aliases: []string{"v"}, - Usage: "View html content", - ArgsUsage: "", - Hidden: true, - Action: func(cCtx *cli.Context) error { - if cCtx.Args().Len() < 1 { - return fmt.Errorf("invalid number of arguments\nUsage: %s %s", cCtx.App.Name, cCtx.Command.ArgsUsage) - } - - // since we don't check for yaml config, we can use the default node url - // this fn might actually not be used down the line - networkInfos := pkgConfig.NewNetworkConfig(pkgConfig.DefaultNodeURL) - siteAddress := cCtx.Args().Get(0) - - err := viewWebsite(siteAddress, &networkInfos) - if err != nil { - logger.Fatalf("An error occured while attempting to view website %s: %v", siteAddress, err) - } - - return nil - }, - }, - { - Name: "delete", - Aliases: []string{"d"}, - Usage: "Delete a website", - ArgsUsage: "", - Flags: flags, - Action: func(cCtx *cli.Context) error { - if cCtx.Args().Len() < 1 { - return fmt.Errorf("invalid number of arguments\nUsage: %s %s", cCtx.App.Name, cCtx.Command.ArgsUsage) - } - - config, err := yamlConfig.LoadConfig(configPath, nodeURL, nickname) - if err != nil { - return fmt.Errorf("failed to load yaml config: %v", err) - } - - siteAddress := cCtx.Args().Get(0) - - if err := deleteWebsite(siteAddress, config); err != nil { - logger.Fatalf("An error occurred while attempting to delete website %s: %v", siteAddress, err) - } - return nil - }, - }, - }, - } - - err := logger.InitializeGlobal("./deweb-cli.log") - if err != nil { - log.Fatalf("failed to initialize logger: %v", err) - } - - logger.Warnf("This DeWeb CLI is deprecated, please use the new DeWeb CLI") - - if err := app.Run(os.Args); err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - } -} - -func deployWebsite(config *yamlConfig.Config, filepath string) (string, error) { - logger.Debugf("Deploying website contract with config: %+v", config.SCConfig) - - deploymentResult, err := website.Deploy(config.WalletConfig.WalletNickname, &config.NetworkConfig, &config.SCConfig) - if err != nil { - return "", fmt.Errorf("failed to deploy website contract: %v", err) - } - - logger.Infof("Website contract deployed at address: %s", deploymentResult.Address) - - chunks, err := processFileForUpload(filepath) - if err != nil { - return "", fmt.Errorf("failed to process file for upload: %v", err) - } - - logger.Debugf("Uploading %d chunks to website at address: %s", len(chunks), deploymentResult.Address) - - err = uploadChunks(chunks, deploymentResult.Address, config) - if err != nil { - return "", fmt.Errorf("failed to upload chunks: %v", err) - } - - return deploymentResult.Address, nil -} - -func confirmUploadFinality(networkInfos msConfig.NetworkInfos, scAddress string) (bool, error) { - fileName := "index.html" - - websiteBytes, err := website.Fetch(&networkInfos, scAddress, fileName) - if err != nil { - return false, fmt.Errorf("failed to fetch website: %v", err) - } - - if len(websiteBytes) == 0 { - logger.Debugf("upload not final for address %v", scAddress) - return false, nil - } - - return true, nil -} - -func waitForUploadFinality(networkInfos msConfig.NetworkInfos, scAddress string) (bool, error) { - timeout := time.After(finalityTimeout) - ticker := time.NewTicker(finalityTickerInterval) - - defer ticker.Stop() - - logger.Infof("waiting for upload finality for address %s", scAddress) - - for { - select { - case <-timeout: - return false, fmt.Errorf("timeout reached: upload did not finalize within %d seconds", finalityTimeout) - - case <-ticker.C: - final, err := confirmUploadFinality(networkInfos, scAddress) - if err != nil { - return false, err - } - - if final { - return true, nil - } - } - } -} - -func uploadChunks(chunks [][]byte, address string, config *yamlConfig.Config) error { - for i, chunk := range chunks { - logger.Infof("Uploading chunk %d out of %d...", i+1, len(chunks)) - logger.Debugf("Uploading chunk %d with size: %d", i+1, len(chunk)) - - operationID, err := website.UploadChunk(address, config.WalletConfig, &config.NetworkConfig, &config.SCConfig, chunk, i) - if err != nil { - return fmt.Errorf("failed to upload chunk %d: %v", i, err) - } - - logger.Infof("Chunk %d out of %d uploaded with operation ID: %s", i+1, len(chunks), operationID) - } - - return nil -} - -// deleteIfRequired checks if the website has more chunks than the new website -func deleteIfRequired(config *yamlConfig.Config, siteAddress string, editChunksNbr int) error { - client := node.NewClient(config.NetworkConfig.NodeURL) - - fileName := "index.html" - - deployedChunks, err := website.GetNumberOfChunks(client, siteAddress, fileName) - if err != nil { - return fmt.Errorf("failed to get number of chunks for website %s: %v", siteAddress, err) - } - - logger.Debugf("Website %s: %s has %d deployed chunks", siteAddress, fileName, deployedChunks) - - if deployedChunks > int32(editChunksNbr) { - logger.Infof("Website %s has more chunks than the new website, deleting and redeploying", siteAddress) - - if err = deleteWebsite(siteAddress, config); err != nil { - return fmt.Errorf("failed to delete website %s: %v", siteAddress, err) - } - } - - return nil -} - -func processFileForUpload(filepath string) ([][]byte, error) { - websiteBytes, err := utils.ReadFileBytes(filepath) - if err != nil { - return nil, fmt.Errorf("failed to get website zip bytes: %w", err) - } - - return website.DivideIntoChunks(websiteBytes, website.ChunkSize), nil -} - -func viewWebsite(scAddress string, networkInfos *msConfig.NetworkInfos) error { - owner, err := website.GetOwner(networkInfos, scAddress) - if err != nil { - logger.Warnf("failed to get owner of %s: %v", scAddress, err) - } - - logger.Infof("Website owner: %s", owner) - - fileName := "index.html" - - // For debugging cache purposes: - // zipFile, err := webmanager.RequestWebsite(scAddress, networkInfos) - zipFile, err := website.Fetch(networkInfos, scAddress, fileName) - if err != nil { - return fmt.Errorf("failed to request website: %v", err) - } - - // firstCreationTimestamp, err := website.GetFirstCreationTimestamp(networkInfos, scAddress) - // if err != nil { - // logger.Warnf("failed to get first creation timestamp of %s: %v", scAddress, err) - // } - - // lastUpdateTimestamp, err := website.GetLastUpdateTimestamp(networkInfos, scAddress) - // if err != nil { - // logger.Warnf("failed to get last update timestamp of %s: %v", scAddress, err) - // } - - indexFile, err := zipper.ReadFileFromZip(zipFile, fileName) - if err != nil { - return fmt.Errorf("failed to get file %s from zip: %v", fileName, err) - } - - // prettyPrintUnixTimestamp(int64(firstCreationTimestamp), int64(lastUpdateTimestamp)) - - logger.Infof("viewing content for %s:\n %s", scAddress, indexFile) - - return nil -} - -// TODO: delete website from cache if it is deleted from the blockchain -func deleteWebsite(siteAddress string, config *yamlConfig.Config) error { - operationID, err := website.Delete(&config.SCConfig, config.WalletConfig, &config.NetworkConfig, siteAddress) - if err != nil { - return fmt.Errorf("error while deleting website %s: %v", siteAddress, err) - } - - logger.Infof("Website %s deleted with operation ID: %s", siteAddress, *operationID) - - return nil -} diff --git a/server/go.mod b/server/go.mod index 1c0ec439..e26ff601 100644 --- a/server/go.mod +++ b/server/go.mod @@ -13,8 +13,6 @@ require ( github.com/jessevdk/go-flags v1.5.0 github.com/massalabs/station v0.6.4 github.com/massalabs/station-massa-wallet v0.4.3 - github.com/stretchr/testify v1.9.0 - github.com/urfave/cli/v2 v2.27.2 golang.org/x/net v0.17.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -26,7 +24,6 @@ require ( github.com/awnumar/memcall v0.1.2 // indirect github.com/awnumar/memguard v0.22.3 // indirect github.com/btcsuite/btcutil v1.0.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/go-openapi/analysis v0.21.2 // indirect @@ -39,9 +36,8 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/stretchr/testify v1.9.0 // indirect github.com/ybbus/jsonrpc/v3 v3.1.4 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect go.uber.org/atomic v1.10.0 // indirect diff --git a/server/go.sum b/server/go.sum index 7fe4af0d..92dc9467 100644 --- a/server/go.sum +++ b/server/go.sum @@ -23,8 +23,6 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -156,8 +154,6 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -180,15 +176,11 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/ybbus/jsonrpc/v3 v3.1.4 h1:pPmgfWXnqR2GdIlealyCzmV6LV3nxm3w9gwA1B3cP3Y= github.com/ybbus/jsonrpc/v3 v3.1.4/go.mod h1:4HQTl0UzErqWGa6bSXhp8rIjifMAMa55E4D5wdhe768= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= diff --git a/server/int/cli/config.go b/server/int/cli/config.go deleted file mode 100644 index 742b8a4d..00000000 --- a/server/int/cli/config.go +++ /dev/null @@ -1,129 +0,0 @@ -package config - -import ( - "fmt" - "os" - - dewebUtils "github.com/massalabs/deweb-server/int/utils" - CLIConfig "github.com/massalabs/deweb-server/pkg/config" - msConfig "github.com/massalabs/station/int/config" - "github.com/massalabs/station/pkg/logger" - "gopkg.in/yaml.v2" -) - -type yamlWalletConfig struct { - WalletNickname string `yaml:"wallet_nickname"` -} - -type yamlScConfig struct { - MaxGas uint64 `yaml:"max_gas"` - MaxCoins uint64 `yaml:"max_coins"` - Expiry uint64 `yaml:"expiry"` -} - -type yamlConfig struct { - WalletConfig *yamlWalletConfig `yaml:"wallet_config"` - ScConfig *yamlScConfig `yaml:"sc_config"` - NodeUrl string `yaml:"node_url"` -} - -type Config struct { - WalletConfig CLIConfig.WalletConfig - SCConfig CLIConfig.SCConfig - NetworkConfig msConfig.NetworkInfos -} - -func LoadConfig(configPath string, nodeURL string, nickname string) (*Config, error) { - if nodeURL == "" { - logger.Warnf("Node URL is empty, using default value") - nodeURL = CLIConfig.DefaultNodeURL - } - - if configPath != "" { - logger.Infof("Loading config from file: %s", configPath) - return loadYamlCliConfig(configPath, nodeURL, nickname) - } - - logger.Infof("No config file specified, using default values") - - return defaultCliConfig(nodeURL, nickname) -} - -func defaultCliConfig(nodeURL string, nickname string) (*Config, error) { - walletConfig := CLIConfig.NewWalletConfig(nickname, nodeURL) - scConfig := CLIConfig.NewSCConfig(nodeURL) - networkInfos := CLIConfig.NewNetworkConfig(nodeURL) - - return &Config{ - WalletConfig: walletConfig, - SCConfig: scConfig, - NetworkConfig: networkInfos, - }, nil -} - -func loadYamlCliConfig(configPath string, nodeURL string, nickname string) (*Config, error) { - if _, err := os.Stat(configPath); os.IsNotExist(err) { - logger.Warnf("Config file does not exist, using default values") - return defaultCliConfig(nodeURL, nickname) - } - - filebytes, err := dewebUtils.ReadFileBytes(configPath) - if err != nil { - return nil, fmt.Errorf("failed to read file bytes: %w", err) - } - - var yamlConf yamlConfig - - err = yaml.Unmarshal(filebytes, &yamlConf) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal YAML data: %w", err) - } - - // Set default values if not specified in the YAML file - - if nickname != "" { - logger.Warnf("Setting wallet nickname to: %s", nickname) - yamlConf.WalletConfig.WalletNickname = nickname - } - - if nodeURL != "" { - logger.Warnf("Setting config node url to: %s", nodeURL) - yamlConf.NodeUrl = nodeURL - } - - newScConfig := CLIConfig.NewSCConfig(yamlConf.NodeUrl) - - if yamlConf.ScConfig.MaxGas == 0 { - logger.Warnf("Max gas is empty, using default value") - yamlConf.ScConfig.MaxGas = newScConfig.MaxGas - } - - if yamlConf.ScConfig.MaxCoins == 0 { - logger.Warnf("Max coins is empty, using default value") - yamlConf.ScConfig.MaxCoins = newScConfig.MaxCoins - } - - if yamlConf.ScConfig.Expiry == 0 { - logger.Warnf("Expiry is empty, using default value") - yamlConf.ScConfig.Expiry = newScConfig.Expiry - } - - walletConfig := CLIConfig.WalletConfig{ - WalletNickname: yamlConf.WalletConfig.WalletNickname, - } - - scConfig := CLIConfig.SCConfig{ - MinimalFees: newScConfig.MinimalFees, // minimal fees is not in the yaml file - MaxGas: yamlConf.ScConfig.MaxGas, - MaxCoins: yamlConf.ScConfig.MaxCoins, - Expiry: yamlConf.ScConfig.Expiry, - } - - networkInfos := CLIConfig.NewNetworkConfig(yamlConf.NodeUrl) - - return &Config{ - WalletConfig: walletConfig, - SCConfig: scConfig, - NetworkConfig: networkInfos, - }, nil -} diff --git a/server/pkg/config/sc.go b/server/pkg/config/sc.go deleted file mode 100644 index 5e780ca5..00000000 --- a/server/pkg/config/sc.go +++ /dev/null @@ -1,60 +0,0 @@ -package config - -import ( - "github.com/massalabs/station-massa-wallet/pkg/utils" - "github.com/massalabs/station/pkg/logger" - "github.com/massalabs/station/pkg/node" -) - -type SCConfig struct { - MinimalFees uint64 - MaxGas uint64 - MaxCoins uint64 - Expiry uint64 -} - -const ( - DefaultMinimalFees = uint64(100_000_000) - DefaultMaxGas = uint64(3_980_167_295) - DefaultMaxCoins = uint64(10_000_000_000) - DefaultExpiry = uint64(3) - NoCoins = uint64(0) -) - -// Returns a new Config for call sc's -func NewSCConfig(NodeURL string) SCConfig { - client := node.NewClient(NodeURL) - - var minimalFees uint64 - - status, err := node.Status(client) - if err != nil { - logger.Errorf("unable to get node status: %v", err) - } - - minimalFees = getMinimalFees(status) - - return SCConfig{ - MinimalFees: minimalFees, - MaxGas: DefaultMaxGas, - MaxCoins: DefaultMaxCoins, - Expiry: DefaultExpiry, - } -} - -// returns minimal fees from node status -func getMinimalFees(status *node.State) uint64 { - minimalFees := DefaultMinimalFees - - if status.MinimalFees != nil { - statusMinimalFees, err := utils.MasToNano(*status.MinimalFees) - if err != nil { - logger.Errorf("unable to convert minimal fees: %v", err) - logger.Warnf("Using default value of %dnMAS for minimal fees", minimalFees) - } else { - minimalFees = statusMinimalFees - } - } - - return minimalFees -} diff --git a/server/pkg/config/wallet.go b/server/pkg/config/wallet.go deleted file mode 100644 index 9a4eab0c..00000000 --- a/server/pkg/config/wallet.go +++ /dev/null @@ -1,13 +0,0 @@ -package config - -type WalletConfig struct { - WalletNickname string - NodeUrl string -} - -func NewWalletConfig(walletNickname string, nodeURL string) WalletConfig { - return WalletConfig{ - WalletNickname: walletNickname, - NodeUrl: nodeURL, - } -} diff --git a/server/pkg/website/chunk.go b/server/pkg/website/chunk.go deleted file mode 100644 index 4a6c74b8..00000000 --- a/server/pkg/website/chunk.go +++ /dev/null @@ -1,61 +0,0 @@ -package website - -import ( - "fmt" - - "github.com/massalabs/station/pkg/convert" - "github.com/massalabs/station/pkg/node/sendoperation" -) - -// WILL BE DELETED SOON -func DivideIntoChunks(data []byte, chunkSize int) [][]byte { - if data == nil || chunkSize <= 0 { - return nil - } - - var chunks [][]byte - - for i := 0; i < len(data); i += chunkSize { - end := i + chunkSize - if end > len(data) { - end = len(data) - } - - chunks = append(chunks, data[i:end]) - } - - return chunks -} - -// WILL BE DELETED SOON -// ComputeChunkCost computes the cost of uploading a chunk to a website. -// The cost is computed based on the size of the chunk and the index of the chunk. -// The cost of the first chunk includes the cost of nbChunk key creation. -// -// TODO: This function should be updated to avoid sending coins for chunks that do not require it. -// - chunk X in storage has chunkSize bytes, so we should not send coins for it. -// - chunk X in storage has 30% of chunkSize bytes, so we should only the missing 70% of chunkSize bytes in coins. -func ComputeChunkCost(chunkIndex int, chunkSize int) (int, error) { - uploadCost, err := sendoperation.StorageCostForEntry(convert.BytesPerUint32, chunkSize) - if err != nil { - return 0, fmt.Errorf("unable to compute storage cost for chunk upload: %w", err) - } - - // if chunkIndex == 0 { - // chunkKeyCost, err := sendoperation.StorageCostForEntry(len([]byte(nbChunkKey)), convert.BytesPerUint32) - // if err != nil { - // return 0, fmt.Errorf("unable to compute storage cost for nbChunk key creation: %w", err) - // } - - // uploadCost += chunkKeyCost - - // lastUpdateKeyCost, err := sendoperation.StorageCostForEntry(len([]byte(lastUpdateTimestampKey)), convert.BytesPerUint64) - // if err != nil { - // return 0, fmt.Errorf("unable to compute storage cost for lastUpdate key creation: %w", err) - // } - - // uploadCost += lastUpdateKeyCost - // } - - return uploadCost, nil -} diff --git a/server/pkg/website/chunk_test.go b/server/pkg/website/chunk_test.go deleted file mode 100644 index c98f3ab9..00000000 --- a/server/pkg/website/chunk_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package website - -import ( - _ "embed" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestChunk(t *testing.T) { - tests := []struct { - name string - data []byte - chunkSize int - }{ - {"Empty byte array", []byte(nil), 2}, - {"Nil chunkSize", []byte("Hello"), 0}, - {"Nominal test case", []byte("Hello, World!"), 1}, - {"Median", []byte("Hello, World!"), 4}, - {"Big byte array", []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit."), 16}, - {"Small byte array", []byte("hello"), 32}, - {"Single character", []byte("a"), 2}, - {"Exact divisible length", []byte("123456"), 2}, - {"Long sentence", []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."), 3}, - {"Website deployer wasm", sc, ChunkSize}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - chunks := DivideIntoChunks(test.data, test.chunkSize) - - if test.data == nil || test.chunkSize <= 0 { - assert.Nil(t, chunks) - return - } - - expectedLen := (len(test.data) + test.chunkSize - 1) / test.chunkSize - assert.Equal(t, len(chunks), expectedLen) - - expectedLastChunkLen := len(test.data) % test.chunkSize - if expectedLastChunkLen == 0 && len(test.data) > 0 { - expectedLastChunkLen = test.chunkSize - } - - // Assert the length of each chunk except the last one - for i := 0; i < len(chunks)-1; i++ { - assert.Equal(t, test.chunkSize, len(chunks[i]), "Chunk size does not match the expected value.") - } - - // Assert the length of the last chunk - if len(chunks) > 0 { - lastChunk := chunks[len(chunks)-1] - assert.Equal(t, expectedLastChunkLen, len(lastChunk), "The length of the last chunk does not match the expected value.") - } - }) - } -} diff --git a/server/pkg/website/delete.go b/server/pkg/website/delete.go deleted file mode 100644 index 476ffcee..00000000 --- a/server/pkg/website/delete.go +++ /dev/null @@ -1,38 +0,0 @@ -package website - -import ( - _ "embed" - "fmt" - - "github.com/massalabs/deweb-server/pkg/config" - msConfig "github.com/massalabs/station/int/config" - "github.com/massalabs/station/pkg/node/sendoperation" - "github.com/massalabs/station/pkg/node/sendoperation/signer" - "github.com/massalabs/station/pkg/onchain" -) - -func Delete(scConfig *config.SCConfig, - walletConfig config.WalletConfig, - networkInfos *msConfig.NetworkInfos, address string, -) (*string, error) { - res, err := onchain.CallFunction( - networkInfos, - walletConfig.WalletNickname, - address, - "deleteWebsite", - []byte{}, - scConfig.MinimalFees, - scConfig.MaxGas, - config.NoCoins, - scConfig.Expiry, - false, - sendoperation.OperationBatch{}, - &signer.WalletPlugin{}, - "Deleting website chunks", - ) - if err != nil { - return nil, fmt.Errorf("deleting website: %w", err) - } - - return &res.OperationResponse.OperationID, nil -} diff --git a/server/pkg/website/deploy.go b/server/pkg/website/deploy.go deleted file mode 100644 index 28b7d6b4..00000000 --- a/server/pkg/website/deploy.go +++ /dev/null @@ -1,49 +0,0 @@ -package website - -import ( - _ "embed" - "fmt" - - pkgConfig "github.com/massalabs/deweb-server/pkg/config" - msConfig "github.com/massalabs/station/int/config" - "github.com/massalabs/station/pkg/node/sendoperation" - "github.com/massalabs/station/pkg/node/sendoperation/signer" - "github.com/massalabs/station/pkg/onchain" -) - -//go:embed sc/websiteDeployer.wasm -var sc []byte - -type DeploymentResult struct { - Address string - OperationID string -} - -func Deploy(walletNickname string, networkInfos *msConfig.NetworkInfos, scConfig *pkgConfig.SCConfig) (*DeploymentResult, error) { - res, evt, err := onchain.DeploySC( - networkInfos, - walletNickname, - scConfig.MaxGas, - scConfig.MaxCoins, - scConfig.MinimalFees, - scConfig.Expiry, - sc, - nil, - sendoperation.OperationBatch{}, - &signer.WalletPlugin{}, - "Deploying website contract", - ) - if err != nil { - return nil, fmt.Errorf("deploying website contract: %w", err) - } - - address, found := onchain.FindDeployedAddress(evt) - if !found { - return nil, fmt.Errorf("deployed contract address not found") - } - - return &DeploymentResult{ - Address: address, - OperationID: res.OperationID, - }, nil -} diff --git a/server/pkg/website/sc/websiteDeployer.wasm b/server/pkg/website/sc/websiteDeployer.wasm deleted file mode 100644 index 36e28ed5..00000000 Binary files a/server/pkg/website/sc/websiteDeployer.wasm and /dev/null differ diff --git a/server/pkg/website/upload.go b/server/pkg/website/upload.go deleted file mode 100644 index ac7dc575..00000000 --- a/server/pkg/website/upload.go +++ /dev/null @@ -1,85 +0,0 @@ -package website - -import ( - "fmt" - - pkgConfig "github.com/massalabs/deweb-server/pkg/config" - mwUtils "github.com/massalabs/station-massa-wallet/pkg/utils" - msConfig "github.com/massalabs/station/int/config" - "github.com/massalabs/station/pkg/convert" - "github.com/massalabs/station/pkg/logger" - "github.com/massalabs/station/pkg/node/sendoperation" - "github.com/massalabs/station/pkg/node/sendoperation/signer" - "github.com/massalabs/station/pkg/onchain" -) - -const ( - appendFunction = "appendBytesToWebsite" -) - -func UploadChunk( - websiteAddress string, - walletConfig pkgConfig.WalletConfig, - networkInfos *msConfig.NetworkInfos, - scConfig *pkgConfig.SCConfig, - chunk []byte, - chunkIndex int, -) (operationID string, err error) { - if !mwUtils.IsValidAddress(websiteAddress) { - return "", fmt.Errorf("invalid website address") - } - - if len(chunk) == 0 { - return "", fmt.Errorf("chunk is empty, no data to upload") - } - - params := prepareUploadParams(chunk, chunkIndex) - - uploadCost, err := ComputeChunkCost(chunkIndex, len(chunk)) - if err != nil { - return "", fmt.Errorf("computing chunk cost: %w", err) - } - - logger.Debugf("Uploading chunk %d to website at address %s with %d nMAS", chunkIndex+1, websiteAddress, uploadCost) - - return performUpload(scConfig, walletConfig, networkInfos, websiteAddress, params, uploadCost, chunkIndex) -} - -func prepareUploadParams(chunk []byte, chunkIndex int) []byte { - params := convert.I32ToBytes(chunkIndex) - params = append(params, convert.U32ToBytes(len(chunk))...) - params = append(params, chunk...) - - return params -} - -func performUpload( - scConfig *pkgConfig.SCConfig, - walletConfig pkgConfig.WalletConfig, - networkInfos *msConfig.NetworkInfos, - websiteAddress string, - params []byte, - uploadCost int, - chunkIndex int, -) (string, error) { - res, err := onchain.CallFunction( - networkInfos, - walletConfig.WalletNickname, - websiteAddress, - appendFunction, - params, - scConfig.MinimalFees, - scConfig.MaxGas, - uint64(uploadCost), - scConfig.Expiry, - false, - sendoperation.OperationBatch{}, - &signer.WalletPlugin{}, - fmt.Sprintf("Uploading chunk %d", chunkIndex), - ) - if err != nil { - return "", fmt.Errorf("uploading chunk %d failed: %w", chunkIndex, err) - } - - return res.OperationResponse.OperationID, nil -}