Skip to content

Commit

Permalink
acl cli
Browse files Browse the repository at this point in the history
  • Loading branch information
goran-ethernal committed Jun 3, 2024
1 parent aa4b8a4 commit c8eead9
Show file tree
Hide file tree
Showing 8 changed files with 756 additions and 89 deletions.
72 changes: 72 additions & 0 deletions cmd/acl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# ACL - tool for managing access lists

In the root of `Erigon` project, use this command to build the commands:

```shell
make acl
```

It can then be run using the following command

```shell
./buid/bin/acl sub-command options...
```

Snapshots supports the following sub commands:

## mode - access list mode

This command takes the following form:

```shell
acl mode <data-dir> <mode>
```

## supported ACL Types
-`allowlist` - allow list type
- `blocklist` - block list type

## supported policies
- `sendTx` - enables or disables ability of an account to send transactions (deploy contracts transactions not included).
- `deploy` - enables or disables ability of an account to deploy smart contracts (other transactions not included)

This command updates the `mode` of access list in the `acl` data base. Supported modes are:
- `disabled` - access lists are disabled.
- `allowlist` - allow list is enabled. If address is not in the allow list, it won't be able to send transactions (regular, contract deployment, or both).
- `blocklist` - block list is enabled. If address is in the block list, it won't be able to send transactions (regular, contract deployment, or both).

## update - update access list

This command can be used to update an access list in the `acl` data base.

This command takes the following form:

```shell
acl update <data-dir> <type> <csv>
```
The `update` command will read the `.csv` file provided which should be in format `address,"policy1,policy2"`, and update the defined `acl` in the `db`. Note that the `.csv` file is considered as the final state of policies for given `acl` type for defined addresses, meaning, if an address in the `.csv` file has `sendTx` policy, but in `db` it had `deploy`, after this command, it will have `sendTx` in the `db`, there is no appending. Also, it is worth mentioning that using a `.csv` file user can delete addresses from an `acl` table by leaving policies string as empty `""`. This will tell the command that the user wants to remove an address completely from an `acl`.

## add - add a policy to an account

This command can be used to add a policy to an account in the specified `acl`.

This command takes the following form:

```shell
acl add <data-dir> <type> <address> <policy>
```

The `add` command will add the given policy to an account in given access list table if account is not already added to access list table, or if given account does not have that policy.

## remove - removes a policy from an account

This command can be used to remove a policy from an account in the specified `acl`.

This command takes the following form:

```shell
acl remove <data-dir> <type> <address> <policy>
```
The `add` command will remove the given policy to an account in given access list table ifgiven account has that policy.


113 changes: 113 additions & 0 deletions cmd/acl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package acl

import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"

"github.com/ledgerwatch/erigon-lib/common/disk"
"github.com/ledgerwatch/erigon-lib/common/mem"
"github.com/ledgerwatch/erigon/cmd/acl/mode"
"github.com/ledgerwatch/erigon/cmd/acl/update"
"github.com/ledgerwatch/erigon/cmd/snapshots/sync"
"github.com/ledgerwatch/erigon/cmd/utils"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/turbo/logging"
"github.com/ledgerwatch/log/v3"
"github.com/urfave/cli/v2"
)

func main() {
logging.LogVerbosityFlag.Value = log.LvlError.String()
logging.LogConsoleVerbosityFlag.Value = log.LvlError.String()

app := cli.NewApp()
app.Name = "acl"
app.Version = params.VersionWithCommit(params.GitCommit)

app.Commands = []*cli.Command{
&mode.Command,
&update.UpdateCommand,
&update.RemoveCommand,
&update.AddCommand,
}

app.Flags = []cli.Flag{}

app.UsageText = app.Name + ` [command] [flags]`

app.Action = func(context *cli.Context) error {
if context.Args().Present() {
var goodNames []string
for _, c := range app.VisibleCommands() {
goodNames = append(goodNames, c.Name)
}
_, _ = fmt.Fprintf(os.Stderr, "Command '%s' not found. Available commands: %s\n", context.Args().First(), goodNames)
cli.ShowAppHelpAndExit(context, 1)
}

return nil
}

for _, command := range app.Commands {
command.Before = func(ctx *cli.Context) error {
logger, err := setupLogger(ctx)

if err != nil {
return err
}

var cancel context.CancelFunc

ctx.Context, cancel = context.WithCancel(sync.WithLogger(ctx.Context, logger))

// setup periodic logging and prometheus updates
go mem.LogMemStats(ctx.Context, logger)
go disk.UpdateDiskStats(ctx.Context, logger)

go handleTerminationSignals(cancel, logger)

return nil
}
}

if err := app.Run(os.Args); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

// setupLogger sets up the logger for the command
func setupLogger(ctx *cli.Context) (log.Logger, error) {
dataDir := ctx.String(utils.DataDirFlag.Name)

if len(dataDir) > 0 {
logsDir := filepath.Join(dataDir, "logs")

if err := os.MkdirAll(logsDir, 0755); err != nil {
return nil, err
}
}

logger := logging.SetupLoggerCtx("acl-"+ctx.Command.Name, ctx, log.LvlError, log.LvlInfo, false)

return logger, nil
}

// handleTerminationSignals handles termination signals
func handleTerminationSignals(stopFunc func(), logger log.Logger) {
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, syscall.SIGTERM, syscall.SIGINT)

switch s := <-signalCh; s {
case syscall.SIGTERM:
logger.Info("Stopping")
stopFunc()
case syscall.SIGINT:
logger.Info("Terminating")
os.Exit(-int(syscall.SIGINT))
}
}
59 changes: 59 additions & 0 deletions cmd/acl/mode/mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package mode

import (
"errors"

"github.com/ledgerwatch/erigon/cmd/snapshots/sync"
"github.com/ledgerwatch/erigon/cmd/utils"
"github.com/ledgerwatch/erigon/zk/txpool"
"github.com/urfave/cli/v2"
)

var (
mode string // Mode of the ACL
)

var Command = cli.Command{
Action: run,
Name: "mode",
Usage: "Set the mode of the ACL",
Flags: []cli.Flag{
&utils.DataDirFlag,
&cli.StringFlag{
Name: "mode",
Usage: "Mode of the ACL (whitelist, blacklist or disabled)",
Destination: &mode,
},
},
}

func run(cliCtx *cli.Context) error {
logger := sync.Logger(cliCtx.Context)

if !cliCtx.IsSet(utils.DataDirFlag.Name) {
return errors.New("data directory is not set")
}

if mode == "" {
return errors.New("mode is not set")
}

dataDir := cliCtx.String(utils.DataDirFlag.Name)

logger.Info("Setting mode", "mode", mode, "dataDir", dataDir)

aclDB, err := txpool.OpenACLDB(cliCtx.Context, dataDir)
if err != nil {
logger.Error("Failed to open ACL database", "err", err)
return err
}

if err := txpool.SetMode(cliCtx.Context, aclDB, mode); err != nil {
logger.Error("Failed to set acl mode", "err", err)
return err
}

logger.Info("ACL Mode set", "mode", mode)

return nil
}
Loading

0 comments on commit c8eead9

Please sign in to comment.