Flow Gateway Node setup

Prerequisites

Generate Node Information

# get the binary
curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/boot-tools.tar
# untar it
tar -xvf boot-tools.tar
# verify sha256sum: a06e3e9b2443c6755214150e9e101b70dd48ae30ffcfcbbcc471ba430cb104bf
sha256sum ./boot-tools/bootstrap
# create a directory
mkdir ./bootstrap
# Use a fully qualified domain name for YOUR_NODE_ADDRESS_GOES_HERE. Please also include the port number in the network address e.g. flowaccess.mycompany.com:3569
./boot-tools/bootstrap key --address "<YOUR_NODE_ADDRESS_GOES_HERE>:3569" --role access -o ./bootstrap

Get you node id

cat ./bootstrap/public-root-information/node-id && echo ""

All your private keys should be in the bootstrap folder created earlier. Please take a back up of the entire folder.

Stake 100 FLOW

The minimum 100 is required to prevent certain vulnerabilities in the smart contract that are a result of having a zero minimum stake requirement. Follow this guide to stake using Flow Port

All fields required are generated here:

cat ./bootstrap/public-root-information/node-info.pub.* | jq
{
  "Role": "access",
  "Address": "flowaccess.mycompany.com:3569",
  "NodeID": "e737ec6efbd26ef43bf676911cdc5a11ba15fc6562d05413e6589fccdd6c06d5",
  "Weight": 0,
  "NetworkPubKey": "f493a74704f6961ae7903e062ecd58d990672858eff99aece7bfbccf3aa02de8f1a624ecbf21a01e8b2f4a5854c231fbe218edd7762a34fea881f3958a215305",
  "StakingPubKey": "ae8dcf81f3a70d72036b7ba2c586ed37ed0eb82b9c0a4aab998a8420f98894f94c14f84fa716e93654d3940fc0c8ff4d19b504c90a5b4918b28f421e9d3659dc2b7e246025ebeffea0d83cceefe315d7ed346dbe412fdac51b64997d97d29f7e"
}

Create an address to use with the faucet here on testnet

Verify That Your Node ID Was Selected

On Wednesday at around 12:00 UTC, the staking auction for the current epoch will end and five nodes from candidate list of nodes will be chosen at random by the staking contract to be part of the next epoch. If all 5 slots have been taken from the previous epoch, then no new access nodes will be chosen

There are several ways to verify whether your node was chosen as explained below When you stake the node, the tokens will show up under the tokensCommitted bucket. After the staking auction ends, if the node is selected, the tokens remain in the tokensCommitted bucket and are moved to the tokensStaked bucket at the end of the epoch. If the node is not selected, the tokens are moved to the tokensUnstaked bucket.

# install flow cli
sh -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)"
echo 'export PATH="$PATH:/root/.local/bin"' >> ~/.profile
source ~/.profile

You can check via Flow Port or using flow accounts staking-info

# You can check the balance using Flow Cli. Once you have downloaded and installed Flow Cli, you can query the account balance using the command
flow accounts staking-info your_account_address -n mainnet
# You can check the balance using Flow Cli. Once you have downloaded and installed Flow Cli, you can query the account balance using the command
flow accounts staking-info your_account_address -n testnet

Look for the Tokens Staked field in the response of the above command to verify

Get binaries

curl -sL -O storage.googleapis.com/flow-genesis-bootstrap/binary/access/app
chmod +x app
mv app /usr/bin/access-node

Create services

Use systemctl to set up services for Access Node, Gateway

Access Node

# Define the variables
NODE_ID=$(cat ./bootstrap/public-root-information/node-info.pub.* | jq -r .NodeID)
DYNAMIC_ACCESS_ADDRESS="secure.mainnet.nodes.onflow.org:9001"
DYNAMIC_ACCESS_PUBLICKEY="28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae"
# Define the variables
NODE_ID=$(cat ./bootstrap/public-root-information/node-info.pub.* | jq -r .NodeID)
DYNAMIC_ACCESS_ADDRESS="secure.testnet.nodes.onflow.org:9001"
DYNAMIC_ACCESS_PUBLICKEY="ba69f7d2e82b9edf25b103c195cd371cf0cc047ef8884a9bbe331e62982d46daeebf836f7445a2ac16741013b192959d8ad26998aff12f2adc67a99e1eb2988d"

sudo tee <<EOF >/dev/null /etc/systemd/system/access-node.service
[Unit]
Description=Access Node daemon
After=network-online.target

[Service]
User=$USER
ExecStart=/usr/bin/access-node \
--nodeid=$NODE_ID \
--bootstrapdir=$PWD/bootstrap \
--datadir=$PWD/data/protocol \
--secretsdir=$PWD/data/secrets \
--execution-data-dir=$PWD/data/execution_data \
--rpc-addr=0.0.0.0:9000 \
--secure-rpc-addr=0.0.0.0:9001 \
--http-addr=0.0.0.0:8000 \
--rest-addr=0.0.0.0:8070 \
--admin-addr=localhost:9002 \
--bind=0.0.0.0:3569 \
--dht-enabled=false \
--grpc-compressor=gzip \
--profiler-dir=$PWD/data/profiler \
--dynamic-startup-access-address=$DYNAMIC_ACCESS_ADDRESS \
--dynamic-startup-access-publickey=$DYNAMIC_ACCESS_PUBLICKEY \
--dynamic-startup-epoch-phase=EpochPhaseStaking
Restart=always
RestartSec=3
LimitNOFILE=4096

[Install]
WantedBy=multi-user.target
EOF

cat /etc/systemd/system/access-node.service
sudo systemctl enable access-node

Build gateway

git clone https://github.com/onflow/flow-evm-gateway.git
cd flow-evm-gateway
go build -o evm-gateway cmd/main/main.go
mv evm-gateway /usr/bin/

EVM Gateway

Each EVM Gateway operator needs to create an account on Flow as well as an account on EVM. The first one will be used to pay for fees on Flow, which means it needs to be sufficiently funded and monitored for balance (it shouldn’t fall to 0 without refunding it, as of now the node doesn’t monitor these, but will be added in the future, however, the funding won’t so it should be done manually). The second EVM account will be used to get refunded fees on EVM. That account shouldn’t have to be monitored for balance as the balance will always grow.

flow keys generate

It will generate an output like this

🔴️ Store private key safely and don't share with anyone!
Private Key              5438b13e290b257f0c41e3b23fbf3b5f5f6d4e9b2d3797430d2d2d5484db9b37
Public Key               9b85626369efe380ebd701f7189f2746fda26d09e1b63cb003bd84a5d33b662685c56427a0526a670efa88b0cb8da371cf9dc1de5ac6bbffb56e327a5c16e708
Mnemonic                 sustain limb elbow awkward onion crouch truth trial until poverty famous feel
Derivation Path          m/44'/539'/0'/0/0
Signature Algorithm      ECDSA_P256

Visit https://faucet.flow.com, and use the generated Public Key, to create and fund your Flow account. Make sure to use the Flow address and the Private Key for the —coa-address & —coa-key flags.

ACCESS_NODE_GRPC_HOST="your_domian:9000"
FLOW_NETWORK_ID="flow-mainnet"
INIT_CADENCE_HEIGHT="211176670" # to be confirmed
COINBASE="your_evm_address_without_0x"
COA_ADDRESS="your_flow_address"
COA_KEY="your_private_key"
GAS_PRICE="100" # feel free to experiment with different values
ACCESS_NODE_GRPC_HOST="your_domian:9000"
FLOW_NETWORK_ID="flow-testnet"
INIT_CADENCE_HEIGHT="211176670"
COINBASE="your_evm_address_without_0x"
COA_ADDRESS="your_flow_address"
COA_KEY="your_private_key"
GAS_PRICE="100" # feel free to experiment with different values
sudo tee <<EOF >/dev/null /etc/systemd/system/gateway.service
[Unit]
Description=Gateway daemon
After=network-online.target

[Service]
User=$USER
ExecStart=/usr/bin/evm-gateway \
--access-node-grpc-host=$ACCESS_NODE_GRPC_HOST \
--flow-network-id=$FLOW_NETWORK_ID \
--init-cadence-height=$INIT_CADENCE_HEIGHT \
--ws-enabled=true \
--coa-resource-create=true \
--coinbase=$COINBASE \
--coa-address=$COA_ADDRESS \
--coa-key=$COA_KEY \
--gas-price=$GAS_PRICE
Restart=always
RestartSec=3
LimitNOFILE=4096

[Install]
WantedBy=multi-user.target
EOF

cat /etc/systemd/system/gateway.service
sudo systemctl enable gateway

Start all services

Order of operations:

  1. access-node: ensure it’s fully synced before proceeding
  2. gateway
sudo systemctl daemon-reload
sudo systemctl restart access-node
sudo systemctl restart gateway

For access node, Compare the flow height explorer mainnet testnet

flow blocks get latest --host localhost:9000

For gateway

curl -s -XPOST 'localhost:8545' --header 'Content-Type: application/json' --data-raw '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq

Check logs

# change log settings to persistent if not already
sed -i 's/#Storage=auto/Storage=persistent/g' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald

journalctl -u access-node.service -f -n 100
journalctl -u gateway.service -f -n 100

Logs should look like

{"level":"info","component":"ingestion","cadence-height":211179523,"cadence-event-length":1,"time":"2024-09-07T15:35:08Z","message":"received new cadence evm events"}
{"level":"info","component":"ingestion","hash":"0xa3e86dbe8a454d7f84908fc3af5ea3e335f4ab33bce8127f43243eb987505020","evm-height":2853,"cadence-height":211179523,"cadence-id":"872cda9894505a8357daa493d45fa99d2632b8a36a556e013df01506c5f893da","parent-hash":"0xa9b37ac67550b5b96490270b49b78fca35ff701b92bf37a6b7f6193050681bf4","tx-hashes-root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","time":"2024-09-07T15:35:08Z","message":"new evm block executed event"}
{"level":"info","component":"ingestion","cadence-height":211179524,"cadence-event-length":1,"time":"2024-09-07T15:35:08Z","message":"received new cadence evm events"}
{"level":"info","component":"ingestion","hash":"0x0c7706407fd79496a845c2a337ecbf551fb670ba5ff864e42d94b6897d71474b","evm-height":2854,"cadence-height":211179524,"cadence-id":"5bd1d53fe3e3125d980dee8d9a75b8998d64d1710acacc1f4df0ad52ab4140f6","parent-hash":"0xa3e86dbe8a454d7f84908fc3af5ea3e335f4ab33bce8127f43243eb987505020","tx-hashes-root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","time":"2024-09-07T15:35:08Z","message":"new evm block executed event"}
{"level":"info","component":"ingestion","cadence-height":211179525,"cadence-event-length":1,"time":"2024-09-07T15:35:08Z","message":"received new cadence evm events"}
{"level":"info","component":"ingestion","hash":"0x42d7665cc17c04170eb77e2b14f7adbfbf30a5ac65d5b36a98a2857798a7a33f","evm-height":2855,"cadence-height":211179525,"cadence-id":"df6a5ddbd669f56c44dc1f4c6701e00c323eedc6a6cd0a14593aeeed9000ea25","parent-hash":"0x0c7706407fd79496a845c2a337ecbf551fb670ba5ff864e42d94b6897d71474b","tx-hashes-root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","time":"2024-09-07T15:35:08Z","message":"new evm block executed event"}
{"level":"info","component":"ingestion","cadence-height":211179526,"cadence-event-length":1,"time":"2024-09-07T15:35:08Z","message":"received new cadence evm events"}
{"level":"info","component":"ingestion","hash":"0x7e248dd506b721faeece565382d1f310665c2faa5a0882b49f039b73eddb0b34","evm-height":2856,"cadence-height":211179526,"cadence-id":"d34dc88006ebd8ce3e82af11d9668f864c7a9a274e4583c392fe367fc210294c","parent-hash":"0x42d7665cc17c04170eb77e2b14f7adbfbf30a5ac65d5b36a98a2857798a7a33f","tx-hashes-root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","time":"2024-09-07T15:35:08Z","message":"new evm block executed event"}
{"level":"info","component":"ingestion","cadence-height":211179527,"cadence-event-length":1,"time":"2024-09-07T15:35:08Z","message":"received new cadence evm events"}
{"level":"info","component":"ingestion","hash":"0x133702b182bdff543bfccd0bf380b28a6b4a9de2c1d2123b14601b522bd49a33","evm-height":2857,"cadence-height":211179527,"cadence-id":"e886a98d565f11119f6f38950145c7c86ebf438dbd6c296d88bfac8d72857ccc","parent-hash":"0x7e248dd506b721faeece565382d1f310665c2faa5a0882b49f039b73eddb0b34","tx-hashes-root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","time":"2024-09-07T15:35:08Z","message":"new evm block executed event"}
Edit this page