Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI commands on binary #616

Merged
merged 17 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN go mod download
RUN go mod verify

# Build binary
RUN CGO_ENABLED=1 go build -o bin -ldflags="-X github.com/onflow/flow-evm-gateway/api.Version=${GATEWAY_VERSION}" ./cmd/main/main.go
RUN CGO_ENABLED=1 go build -o bin -ldflags="-X github.com/onflow/flow-evm-gateway/api.Version=${GATEWAY_VERSION}" cmd/main.go
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Missing 'run' and 'version' command implementations

The build command includes version and run commands, but their implementations are not found in cmd/main.go. Please ensure these commands are properly implemented to align with the PR objectives.

🔗 Analysis chain

Build command updated to support versioning and CGO

The build command has been modified to include version information and enable CGO. This change aligns with the PR objective of adding a version command to the binary.

A few points to note:

  1. CGO_ENABLED=1 allows the use of cgo, which might be necessary for certain dependencies.
  2. The ldflags inject the version information, enabling the new version command.
  3. The build target has changed from ./cmd/main/main.go to cmd/main.go, suggesting a restructure of the project layout.

Let's verify if the new project structure is consistent:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the existence of cmd/main.go and check its content
if [ -f cmd/main.go ]; then
  echo "cmd/main.go exists. Content:"
  cat cmd/main.go
else
  echo "Error: cmd/main.go does not exist"
  exit 1
fi

Length of output: 468

RUN chmod a+x bin

# RUN APP
Expand All @@ -30,4 +30,4 @@ COPY --from=app-builder /app/bin /flow-evm-gateway/app

EXPOSE 8545

ENTRYPOINT ["/flow-evm-gateway/app"]
ENTRYPOINT ["/flow-evm-gateway/app", "run"]
24 changes: 23 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ check-tidy:
go mod tidy
git diff --exit-code

.PHONY: build
build:
CGO_ENABLED=1 go build -o flow-evm-gateway -ldflags="-X github.com/onflow/flow-evm-gateway/api.Version=$(shell git describe --tags --abbrev=0 2>/dev/null || echo 'unknown')" cmd/main.go
chmod a+x flow-evm-gateway

.PHONY: fix-lint
fix-lint:
golangci-lint run -v --fix ./...
Expand Down Expand Up @@ -45,7 +50,24 @@ start:
start-local:
rm -rf db/
rm -rf metrics/data/
go run cmd/main/main.go \
go run cmd/main.go run \
--flow-network-id=flow-emulator \
--coinbase=FACF71692421039876a5BB4F10EF7A439D8ef61E \
--coa-address=f8d6e0586b0a20c7 \
--coa-key=2619878f0e2ff438d17835c2a4561cb87b4d24d72d12ec34569acd0dd4af7c21 \
--wallet-api-key=2619878f0e2ff438d17835c2a4561cb87b4d24d72d12ec34569acd0dd4af7c21 \
--coa-resource-create=true \
--gas-price=0 \
--log-writer=console \
--profiler-enabled=true \
--profiler-port=6060
m-Peter marked this conversation as resolved.
Show resolved Hide resolved

# Use this after running `make build`, to test out the binary
.PHONY: start-local-bin
start-local-bin:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a comment for when you would use what would be nice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 👍
Added comment in f2c6fcc

rm -rf db/
rm -rf metrics/data/
./flow-evm-gateway run \
--flow-network-id=flow-emulator \
--coinbase=FACF71692421039876a5BB4F10EF7A439D8ef61E \
--coa-address=f8d6e0586b0a20c7 \
Expand Down
89 changes: 57 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

**EVM Gateway enables seamless interaction with EVM on Flow, mirroring the experience of engaging with any other EVM blockchain.**

EVM Gateway implements the Ethereum JSON-RPC API for [EVM on Flow](https://developers.flow.com/evm/about) which conforms to the Ethereum [JSON-RPC specification](https://ethereum.github.io/execution-apis/api-documentation/). The EVM Gateway is tailored for integration with the EVM environment on the Flow blockchain. Rather than implementing the full `geth` stack, the JSON-RPC API available in EVM Gateway is a lightweight implementation that uses Flow's underlying consensus and smart contract language, [Cadence](https://cadence-lang.org/docs/), to handle calls received by the EVM Gateway. For those interested in the underlying implementation details, please refer to the [FLIP #243](https://github.com/onflow/flips/issues/243) (EVM Gateway) and [FLIP #223](https://github.com/onflow/flips/issues/223) (EVM on Flow Core) improvement proposals.
EVM Gateway implements the Ethereum JSON-RPC API for [EVM on Flow](https://developers.flow.com/evm/about) which conforms to the Ethereum [JSON-RPC specification](https://ethereum.github.io/execution-apis/api-documentation/). The EVM Gateway is tailored for integration with the EVM environment on the Flow blockchain. Rather than implementing the full `geth` stack, the JSON-RPC API available in EVM Gateway is a lightweight implementation that uses Flow's underlying consensus and smart contract language, [Cadence](https://cadence-lang.org/docs/), to handle calls received by the EVM Gateway. For those interested in the underlying implementation details, please refer to the [FLIP #243](https://github.com/onflow/flips/issues/243) (EVM Gateway) and [FLIP #223](https://github.com/onflow/flips/issues/223) (EVM on Flow Core) improvement proposals.

EVM Gateway is compatible with the majority of standard Ethereum JSON-RPC APIs allowing seamless integration with existing Ethereum-compatible web3 tools via HTTP. EVM Gateway honors Ethereum's JSON-RPC namespace system, grouping RPC methods into categories based on their specific purpose. Each method name is constructed using the namespace, an underscore, and the specific method name in that namespace. For example, the `eth_call` method is located within the `eth` namespace. See below for details on methods currently supported or planned.

### Design

![design ](https://github.com/onflow/flow-evm-gateway/assets/75445744/3fd65313-4041-46d1-b263-b848640d019f)


The basic design of the EVM Gateway consists of a couple of components:

- Event Ingestion Engine: this component listens to all Cadence events that are emitted by the EVM core, which can be identified by the special event type ID `evm.TransactionExecuted` and `evm.BlockExecuted` and decodes and index the data they contain in the payloads.
Expand All @@ -24,15 +23,38 @@ The basic design of the EVM Gateway consists of a couple of components:

**Manual Build**

We recommend using Docker to run the EVM Gateway, as detailed in the subsequent section. Alternatively, if you decide to build the binaries manually, you can do so by running:
We recommend using Docker to run the EVM Gateway, as detailed in the subsequent section. Alternatively, if you decide to build the binary manually, you can do so by running:

```bash
# Make sure you pull the latest changes before running `make build`
git pull origin main
git fetch origin --tags

make build
```
go build -o evm-gateway cmd/main/main.go

To view the binary version:

```bash
./flow-evm-gateway version
```

The binary can then be run using the correct flags (see the table below or the example in the "running" section).
To view all the available flags for running the EVM Gateway Node:

```bash
./flow-evm-gateway help run
```

The binary can then be run by passing the necessary flags:

```bash
./flow-evm-gateway run {flags}
```
./evm-gateway {flags}

To run a local version for development, with the necessary flags set:

```bash
make start-local-bin
```

# Running
Expand All @@ -43,32 +65,28 @@ Operating an EVM Gateway is straightforward. It can either be deployed locally a
**Start Emulator**

To run the gateway locally you need to start the Flow Emulator:
```

```bash
flow emulator
```
_Make sure flow.json has the emulator account configured to address and private key we will use for starting gateway bellow._

Please refer to the configuration section and read through all the configuration flags before proceeding.

Then you need to start the gateway:
```
go run cmd/main/main.go \
--flow-network-id flow-emulator \
--coinbase FACF71692421039876a5BB4F10EF7A439D8ef61E \
--coa-address f8d6e0586b0a20c7 \
--coa-key 2619878f0e2ff438d17835c2a4561cb87b4d24d72d12ec34569acd0dd4af7c21 \
--coa-resource-create \
--gas-price 0
Then you can start the EVM Gateway with:

```bash
make start-local
```

Note that the gateway will be starting from the latest emulator block, so if the emulator is run before and transactions happen in the meantime, the gateway will not fetch those historical blocks & transactions.
Note that the gateway will be starting from the latest emulator block, so if the emulator is run before any transactions happen in the meantime, the gateway will not fetch those historical blocks & transactions.
This will be improved soon.

_In this example we use `coa-address` value set to the service account of the emulator, the same as `coa-key`.
This account will by default be funded with Flow which is a requirement. For `coinbase` we can
use whichever valid EVM address. It's not really useful for local running besides collecting fees. We also allow for the
`coa-resource-create` to auto-create resources needed on start-up on the `coa` account in order to operate the gateway.
`gas-price` is set at 0 so we don't have to fund EOA accounts. We can set it higher but keep in mind you will then
_In the example above we set `coa-address` value to the service account of the emulator, the same as `coa-key`.
This account will by default be funded with Flow which is a requirement. For `coinbase` we can
use whichever valid EVM address. It's not really useful when running locally besides collecting fees. We also allow for the
`coa-resource-create` to auto-create resources needed on start-up on the `coa` account in order to operate the gateway.
`gas-price` is set at 0 so we don't have to fund EOA accounts. We can set it higher but keep in mind you will then
need funded accounts for interacting with EVM._

**With Docker**
Expand Down Expand Up @@ -100,26 +118,32 @@ it should return:
}
```

**Running on Testnet**
### Running on Testnet

Running against the testnet with a local build can be done by pointing the gateway to the testnet ANs and providing the correct configuration.
Running against the testnet with a local build can be done by pointing the gateway to the testnet ANs and providing the correct configuration.
Please refer to the configuration section and read through all the configuration flags before proceeding.

Below is an example configuration for running against testnet, with an already created testnet account.

```
./evm-gateway \
```bash
./flow-evm-gateway run \
--access-node-grpc-host=access.devnet.nodes.onflow.org:9000 \
--access-node-spork-hosts=access-001.devnet51.nodes.onflow.org:9000 \
--flow-network-id=flow-testnet \
--init-cadence-height=211176670 \
--ws-enabled=true \
--coa-resource-create=true \
--coa-resource-create=false \
--coinbase=FACF71692421039876a5BB4F10EF7A439D8ef61E \
--coa-address=0x62631c28c9fc5a91 \
--coa-key=2892fba444f1d5787739708874e3b01160671924610411ac787ac1379d420f49 \
m-Peter marked this conversation as resolved.
Show resolved Hide resolved
--gas-price=100
```

The `--init-cadence-height` is the Flow block height to start indexing from. To index the full EVM state, from its beginning, the proper value for this flag is `211176670`. This is the height where the `EVM` contract was first deployed on testnet, and this is where the EVM state starts from.

If you wish to test this out with your own Access Node, simply set `--access-node-grpc-host` to the location where it is hosted.
**Note:** You need to make sure that your Access Node has indexed at least up to Flow block height `211176670`.

For the `--gas-price`, feel free to experiment with different values.

The `--coinbase` can be any EOA address.
Expand Down Expand Up @@ -163,10 +187,11 @@ Should return a response similar to:
}
```

**Running on Mainnet**
### Running on Mainnet

Running the EVM gateway for mainnet requires additional security and stability measures which are described in this document: https://flowfoundation.notion.site/EVM-Gateway-Deployment-3c41da6710af40acbaf971e22ce0a9fd?pvs=74

For mainnet, the Flow block height where the EVM state starts from is `85981134`. To index the full EVM state, use this value for the `--init-cadence-height` flag.

## Configuration Flags

Expand Down Expand Up @@ -206,7 +231,7 @@ The application can be configured using the following flags at runtime:
| `traces-backfill-start-height` | `0` | Start height for backfilling transaction traces |
| `traces-backfill-end-height` | `0` | End height for backfilling transaction traces |
| `index-only` | `false` | Run in index-only mode, allowing state queries and indexing but no transaction sending |
| `profiler-enabled` | `false` | Enable the pprof profiler server |
| `profiler-enabled` | `false` | Enable the pprof profiler server |
| `profiler-host` | `localhost` | Host for the pprof profiler |
| `profiler-port` | `6060` | Port for the pprof profiler |

Expand Down Expand Up @@ -245,15 +270,15 @@ The EVM Gateway implements APIs according to the Ethereum specification: https:/
* debug_traceTransaction
* debug_traceBlockByNumber
* debug_traceBlockByHash

**Unsupported APIs**
- Wallet APIs: we don't officially support wallet APIs (eth_accounts, eth_sign, eth_signTransaction, eth_sendTransaction) due to security
concerns that come with managing the keys on production environments, however, it is possible to configure the gateway to allow these
methods for local development by using a special flag `--wallet-api-key`.
methods for local development by using a special flag `--wallet-api-key`.
- Proof API: we don't support obtaining proofs yet, Flow piggy-backs on the Flow consensus, and hence the Flow proofs can be used to verify
and trust the EVM environment. We intend to add access to EVM proofs in the future.
- Access Lists: we don't yet support creating access lists as they don't affect the fees we charge. We might support this in the future
to optimize fees, but it currently is not part of our priorities.
to optimize fees, but it currently is not part of our priorities.

# Debugging

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

import (
"os"

"github.com/onflow/flow-evm-gateway/cmd/run"
"github.com/onflow/flow-evm-gateway/cmd/version"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "",
Short: "Utility commands for the EVM Gateway Node",
}
m-Peter marked this conversation as resolved.
Show resolved Hide resolved

func Execute() {
if err := rootCmd.Execute(); err != nil {
log.Err(err).Msg("failed to run command")
os.Exit(1)
}
}
Comment on lines +17 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing error handling in the Execute function.

While the current implementation is functional, consider the following improvements:

  1. Add more context to the error log:
-		log.Err(err).Msg("failed to run command")
+		log.Err(err).Str("command", os.Args[0]).Msg("failed to execute command")
  1. Consider returning the error instead of calling os.Exit(1) directly. This allows for better testability and gives the caller more control over how to handle the error.
-func Execute() {
+func Execute() error {
 	if err := rootCmd.Execute(); err != nil {
 		log.Err(err).Str("command", os.Args[0]).Msg("failed to execute command")
-		os.Exit(1)
+		return err
 	}
+	return nil
}

These changes will provide more informative logs and improve the function's flexibility and testability.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func Execute() {
if err := rootCmd.Execute(); err != nil {
log.Err(err).Msg("failed to run command")
os.Exit(1)
}
}
func Execute() error {
if err := rootCmd.Execute(); err != nil {
log.Err(err).Str("command", os.Args[0]).Msg("failed to execute command")
return err
}
return nil
}


func main() {
rootCmd.AddCommand(version.Cmd)
rootCmd.AddCommand(run.Cmd)

Execute()
}
Comment on lines +24 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in the main function.

The main function currently doesn't handle potential errors from the Execute function. Consider the following improvement:

func main() {
	rootCmd.AddCommand(version.Cmd)
	rootCmd.AddCommand(run.Cmd)

-	Execute()
+	if err := Execute(); err != nil {
+		os.Exit(1)
+	}
}

This change ensures that if Execute returns an error, the program will exit with a non-zero status code, which is a common practice for indicating failure in CLI applications.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func main() {
rootCmd.AddCommand(version.Cmd)
rootCmd.AddCommand(run.Cmd)
Execute()
}
func main() {
rootCmd.AddCommand(version.Cmd)
rootCmd.AddCommand(run.Cmd)
if err := Execute(); err != nil {
os.Exit(1)
}
}

44 changes: 0 additions & 44 deletions cmd/main/main.go

This file was deleted.

Loading
Loading