Set up a Graph Indexer
Go through the following documentation for Docker set up:
Here is the first set of instructions regarding the node:
Setup#Link to this section
- Clone Graph Node and navigate to the Docker directory:
git clone http://github.com/graphprotocol/graph-node
cd graph-node/docker
- For linux users only - Use the host IP address instead of
host.docker.internal
in thedocker-compose.yaml
using the included script:
./setup.sh
- Start a local Graph Node that will connect to your Ethereum endpoint:
docker-compose up
After this, I check
docker ps
and I get the following:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8a4319bf3ee graphprotocol/graph-node "start" 4 weeks ago Up 43 minutes 0.0.0.0:8000-8001->8000-8001/tcp, 0.0.0.0:8020->8020/tcp, 0.0.0.0:8030->8030/tcp, 0.0.0.0:8040->8040/tcp docker-graph-node-1
e0cad25b6f41 postgres "docker-entrypoint.s…" 4 weeks ago Up 43 minutes 0.0.0.0:5432->5432/tcp docker-postgres-1
4a4dad543078 ipfs/go-ipfs:v0.10.0 "/sbin/tini -- /usr/…" 4 weeks ago Up 43 minutes 4001/tcp, 8080-8081/tcp, 4001/udp, 0.0.0.0:5001->5001/tcp docker-ipfs-1
So I have three containers running:
- graph-node
- postgres
- ipfs
According to the docs, within this I have an Ethereum node.
I check the node at port 8000
:
Access deployed subgraphs by deployment ID at /subgraphs/id/<ID> or by name at /subgraphs/name/<NAME>
I then pulled docker images for the indexer agent and indexer service
docker pull ghcr.io/graphprotocol/indexer-service:latest
docker pull ghcr.io/graphprotocol/indexer-agent:latest
I now checked the images pulled:
docker images
This is what I now see:
REPOSITORY TAG IMAGE ID CREATED SIZE
ghcr.io/graphprotocol/indexer-service latest b09771b4daf3 5 weeks ago 2.16GB
ghcr.io/graphprotocol/indexer-agent latest 5bc7f15f61d1 5 weeks ago 2.04GB
postgres latest ceccf204404e 6 weeks ago 379MB
graphprotocol/graph-node latest 37e8e652fc2f 3 months ago 227MB
ipfs/go-ipfs v0.10.0 3e1ffbe25944 20 months ago 77.2MB
The docs then say the following:
- Run the components
docker run -p 7600:7600 -it indexer-service:latest ...
docker run -p 18000:8000 -it indexer-agent:latest ...
NOTE: After starting the containers, the Indexer service should be accessible at http://localhost:7600 and the Indexer agent should be exposing the Indexer management API at http://localhost:18000/.
This seemed confusing because ...
implies arguments are passed, but it immediately describes a running service.
The docs also say the following:
Ethereum node - By default, the docker compose setup will use mainnet: http://host.docker.internal:8545 to connect to the Ethereum node on your host machine. You can replace this network name and url by updating
docker-compose.yaml
.
This wasn't documented, but my understanding is this would mean installing a local node.
Since I wanted to also start in testnet, not mainnet despite what the documentation said, I would need to install Geth or Parity to run locally.
At this point, I wanted to just get something going, so I created a QuickNode Goerli endpoint.
I also found a separate page called The Graph Academy that had slightly different information:
https://docs.thegraph.academy/the-graph-ecosystem/infrastructure/testnet
specifically, it included a table of environment variables for the indexer which are different from what I see in the other document.
That document also highlights some information not found on the other document.
First, it talks about Testnet.
To me, as a first time indexer, I would much prefer to get up and running on Testnet with a faucet of GRT than having to stake on my own right away, which is what the main documentation says to do.
So, here are the instructions:
- join The Graph Discord,
- get the @testnetindexer role in the #roles channel,
- use the #testnet-goerli-faucet channel to obtain testnet GRT.
So to do this, I had to enable the networks in my Metamask, and the easiest way to do this is to go to the chainlist.org directory and search for goerli
However, I added both Ethereum and Arbitum because Arbitum network should be now live. I don't see documentation to that effect, but that's a good thing to check.
Anyway, once I got into the Discord channel I entered:
!grt <public wallet address>
So, once the wallet receives the tokens, you can stake by following the instructions here:
Meanwhile....if you're like me and haven't used the Goerli testnet, you'll want to go to a faucet to pay for gas.
https://faucet.quicknode.com/ethereum/goerli
Note, it's better to start the faucet drip earlier, because there can be delays.
Via Graph Explorer
The Graph Explorer provides an easy way to approve and stake your GRT as an indexer via a web GUI.
-
- Navigate to the testnet explorer
-
- Login with Metamask and select the
Goerli
network
- Login with Metamask and select the
-
- Navigate to your profile (click your address/avatar at top right)
-
- Select the
Indexing
tab and hit theStake
button
- Select the
-
- Follow the directions on the staking screen to stake the desired amount
I am still waiting for my wallet to receive the tokens so....meanwhile....
While you are in the Metamask Wallet, I recommend (again, not clearly documented where I would have expected it) a separate Account from your staking account which is an Operator Wallet from within Metamask.
You'll see why as we update the docker-compose
file.
Now, there are a few things that need clarification (or it did to me, I'm not sure how everyone else figured it out based on these docs):
mnemonic
is going to be for theoperator wallet
which is generated when starting the indexerindexer-address
is also going to be the public Ethereum address of theoperator wallet
so initially this is also left blank
Also, in the docs and initial docker-compose.yaml
file, the postgres DB names are different. I made them the same since I didn't see another postgres application as a docker image, just the one from the graph-node repo.
So, I ran docker-compose up
and got some surprising errors:
For docker-indexer-service-1
:
Missing required arguments: ethereum, mnemonic, indexer-address, graph-node-query-endpoint, graph-node-status-endpoint, postgres-host, postgres-database, network-subgraph-endpoint
So...while the Academy pages lists explicit environiment variables instead of arguments, it's incomplete on this page: https://docs.thegraph.academy/the-graph-ecosystem/infrastructure/testnet
Getting past the 'missing arguments' error for indexer-agent and indexer-service
How I am running these
Although not documented, I use the format that is consistent with the few examples that were documented:
INDEXER_AGENT_{argument in CAPS}
indexer-agent
docker run -p 7600:7600 -it --env-file ./indexer-agent-args.txt --name indexer-agent ghcr.io/graphprotocol/indexer-agent:latest
So I decided to just breakdown what is expected and what are the definitions.
argument | help | docs | academy | random
--- | ---| --- | --- | --- | ---
ethereum | Ethereum node or provider URL string required | | I |
mnemonic | Mnemonic for the operator wallet string required | | |
indexer-address | Ethereum address of the indexer | | |
graph-node-query-endpoint | Graph Node endpoint for querying subgraphs |http://localhost:8000/ | x |
graph-node-status-endpoint | Graph Node endpoint for indexing statuses | http://localhost:8030/graphql | x |
graph-node-admin-endpoint | Graph Node endpoint for applying and updating subgraph deployments | http://localhost:8020/ | x |
public-indexer-url | Indexer endpoint for receiving requests from the network | http://localhost:7600 | x |
index-node-ids | Node IDs of Graph nodes to use for indexing | default| x |
epoch-subgraph-endpoint | Endpoint to query the epoch block oracle subgraph | | x | https://api.thegraph.com/subgraphs/name/graphprotocol/mainnet-epoch-block-oracle ; https://api.thegraph.com/subgraphs/name/graphprotocol/goerli-epoch-block-oracle
postgres-host | Postgres host | localhost | x |
postgres-database | | indexer | x |
Indexer-service
Similar exercise. Source from help can be found in Github:
docker run -p 7600:7600 -it --env-file ./indexer-service-args.txt --name indexer-service ghcr.io/graphprotocol/indexer-service:latest --mnemonic <add here> --indexer-address <add here>
argument | help | docs | academy | random |
---|---|---|---|---|
ethereum | Ethereum node or provider URL | x | x | |
mnemonic | Mnemonic for the operator wallet | x | x | generate |
indexer-address | separate from operator wallet | x | x | generate |
graph-node-query-endpoint | Graph Node endpoint to forward queries to | http://localhost:8000/ | x | |
graph-node-status-endpoint | Graph Node endpoint for indexing statuses etc. | http://localhost:8030/graphql | x | |
postgres-host | ||||
network-subgraph-endpoint | x | https://gateway.thegraph.com/network | ||
postgres-database | is_staging | x |
Even though it isn't documented as such, I was able to create environment variables using the following format:
INDEXER_SERVICE_{argument in CAPS}
This is via the --env-file
where the format is something like this:
INDEXER_SERVICE_GRAPH_NODE_QUERY_ENDPOINT= 'http://localhost:8000/'
INDEXER_SERVICE_GRAPH_NODE_STATUS_ENDPOINT= http://localhost:8030/graphql
INDEXER_SERVICE_POSTGRES_HOST= localhost
So using the same mnemonic
as I used in agent, I am getting invalid mnemonic
!!!
Create a Mnemonic
https://docs.thegraph.academy/official-docs/indexer/testnet/guide
You need a wallet with a seed phrase that is registered as your operator wallet. This wallet will be the one that makes transactions on behalf of your main wallet (which holds and stakes the GRT). The operator wallet has limited functionality, and it's recommended to be used for security reasons.
You need a 12-word, or 15-word mnemonic phrase in order for it to work.
To make yourself a mnemonic eth wallet you can go to this website and just press generate. You get a seed phrase in the input field labeled BIP39 Mnemonic. Scroll down a bit and find the select field labeled Coin. Select ETH as network in the dropdown and you find your address, public key and private key in the first row of the table if you scroll down the page in the section with the heading "Derived Addresses". You can import the wallet using the private key into Metamask.
Although this look good too: https://github.com/glonlas/offline-mnemonic-generator
Better Wallet description
https://github.com/StakeSquid/graphprotocol-testnet-docker/blob/master/docs/pre-requisites.md
Set your Operator
The Operator is a wallet address that is entirely separate from the address which you staked your GRT from. This Operator wallet will be filled with ETH, and will be used to send transactions (such as allocations) to the network, while keeping your Staked GRT safe in case of an attack on your infrastructure. It is highly recommended for you to use a new wallet, generated from a new mnemonic phrase.
For this, follow the instructions here first, then head back for the rest.
Okay, assuming that you followed the instructions and you have your new Operator wallet at hand, let's go and link it up with the wallet that you used to stake your GRT.
- Login with Metamask on the wallet that you used to stake your GRT
- Click the Profile dropdown button, and go to "Settings", and then to the "Operators" tab
- Click the Plus (+) button and add your operator public address there
- Submit the transaction, then you're done
So I used the address generated by the mnemonic....turns out that is wrong after reading further. So.....
Got this msg:
"Indexer and operator are identical, operator status granted"}
https://docs.thegraph.academy/official-docs/indexer/testnet/graph-protocol-testnet-baremetal/4_deployandconfiguregraphindexerstack
This says:
Testnet prerequisites
You will need two Ethereum addresses in order to run your Indexer. One Indexer address and one Operator address.
Indexer = your main address with all privileges. Operator = the address used by the indexer, only has specific privileges to run the indexer software.
If you are deploying to testnet you will need testnet GRT in order to register your Indexing operation on-chain. Check the discord for info on how to register and receive testnet GRT.
I'm not sure what "main address with all privileges" actually means. Or why the operator address generates an error.
So I'll try another public address generated straight from Metamask and see if it still works.
Now I get the following:
TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:372:5)
at URL.onParseError (node:internal/url:553:9)
at new URL (node:internal/url:629:5)
at new AllocationReceiptCollector (/usr/local/lib/node_modules/@graphprotocol/indexer-agent/node_modules/@graphprotocol/indexer-common/dist/allocations/query-fees.js:32:32)
at /usr/local/lib/node_modules/@graphprotocol/indexer-agent/dist/commands/start.js:523:34
at Generator.next (<anonymous>)
at fulfilled (/usr/local/lib/node_modules/@graphprotocol/indexer-agent/dist/commands/start.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
input: 'undefined',
code: 'ERR_INVALID_URL'
Mnemonic troubleshooting
I didn't see anything useful in the Discord's. Other people do seem to have the same error, but no clear resolution.
Current guess is that I need to register the Operator address as part of my profile. Perhaps the mnemonic is saying it is invalid because the Operator address that is generated doesn't match my profile.
Have no idea, though. But I have been blocked adding it because I need Goerli gas and have tried three times from the QuickNode faucet....still nothing:
https://faucet.quicknode.com/ethereum/goerli/?transactionHash=0xe30fcd6b5eba31085045f8c30beed3461bfc9487592abc53d2ea1457b0bf4b82
Alright, so I finally found a faucet which worked. Hassle. Had to go here:
https://faucetlink.to/goerli
And had to try a bunch till I could find one that worked.
Alchemy's did, so that says something about the service.
Now that I have it, I was able to:
- Add the operator address, the derived address from the generated mnemonic (which I did online for now, not the best, but for now....)
- Staked on the Testnet with $GRT
So cleared all the indexer-agent and indexer-service in docker (once I get something running which make sure there's a name for the service as with docker compose for the graph-node), and trying again.
Didn't make a difference adding it in.
According to the API, it's a failed checksum.....???
https://docs.ethers.org/v3/api-advanced.html
ethers . HDNode . mnemonicToEntropy ( mnemonic )
Convert a mnemonic to its binary entropy. (throws an error if the checksum is invalid)
Is the Environment variable wrong? I checked that the mnemonic is correct by comparing the private key generated to what is created after importing into metamask. But it's not the same as the checksum, itself, but I'm right now surprised if the website is generating the wrong mnemonic.
The error message:
Error: invalid mnemonic
at mnemonicToEntropy (/opt/indexer/node_modules/@ethersproject/hdnode/lib/index.js:268:15)
at Function.HDNode.fromMnemonic (/opt/indexer/node_modules/@ethersproject/hdnode/lib/index.js:217:38)
at Function.Wallet.fromMnemonic (/opt/indexer/node_modules/@ethersproject/wallet/lib/index.js:235:43)
at /opt/indexer/packages/indexer-agent/dist/commands/start.js:439:38
at Generator.next (<anonymous>)
at fulfilled (/opt/indexer/packages/indexer-agent/dist/commands/start.js:5:58)
docker run -it --entrypoint /bin/bash ghcr.io/graphprotocol/indexer-agent
cd /opt/indexer/node_modules/@ethersproject/hdnode/lib/
nl index.js
cd /opt/indexer/packages/indexer-agent/dist/commands/
nl start.js
start.js
https://gist.github.com/timfong888/62d037da405512c62a7b226f0272f664
try to pass argument as flag
So this time I passed the --mnemonic
directly as a flag and it worked.
This is strange. It means the environment variable wasn't passing it correctly.
Okay, so now I have passed as arguments --mnemonic
and --indexer-address
and I no longer have the error.
So, once this is working, I now have this:
ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:5432
at Client._connectionCallback (/opt/indexer/node_modules/sequelize/lib/dialects/postgres/connection-manager.js:130:24)
at Client._handleErrorWhileConnecting (/opt/indexer/node_modules/pg/lib/client.js:305:19)
at Client._handleErrorEvent (/opt/indexer/node_modules/pg/lib/client.js:315:19)
at Connection.emit (node:events:527:28)
at Connection.emit (node:domain:475:12)
at Socket.reportStreamError (/opt/indexer/node_modules/pg/lib/connection.js:52:12)
at Socket.emit (node:events:527:28)
at Socket.emit (node:domain:475:12)
at emitErrorNT (node:internal/streams/destroy:157:8)
at emitErrorCloseNT (node:internal/streams/destroy:122:3) {
parent: Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 5432
},
original: Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 5432
}
}
This is out of my depth as to why the local host database isn't working.
The relevant parts of the env file are for the indexer agent, and then I ran the indexer service as well.
Indexer service:
INDEXER_SERVICE_POSTGRES_HOST=127.0.0.1
INDEXER_SERVICE_POSTGRES_PORT= 5432
INDEXER_SERVICE_POSTGRES_USERNAME= indexer-agent
INDEXER_SERVICE_POSTGRES_PASSWORD= let-me-in
INDEXER_SERVICE_POSTGRES_DATABASE= indexer-db
INDEXER_AGENT_POSTGRES_HOST=127.0.0.1
INDEXER_AGENT_POSTRES_PORT=5432
INDEXER_AGENT_POSTGRES_USERNAME= indexer-agent
INDEXER_AGENT_POSTGRES_PASSWORD= let-me-in
INDEXER_AGENT_POSTGRES_DATABASE=indexer-db
Unlock the issue with mnemonic
and indexer-address
which did NOT work when passed through --env-file
it does appear that the port and database are correct. But whether the usernames that I defined here are right is still unclear to me. I just used what is in the docs.
Blocked - try another image
I am blocked.
I am not sure why the mnemonic is invalid since I am following BIP39 from https://iancoleman.io/bip39/
But need to move on for now.
https://thegraph.academy/indexers/setting-up-a-testnet-indexer/
Hm, not making progress this way -- seems like I need to set up archive node spinning up infrastructure. Will look into this later. Back to Mnmonic.
List of Docs
- https://docs.thegraph.academy/the-graph-ecosystem/infrastructure/testnet
- Has some environment variables
- also has some proposed values
2023-05-30
Today I at least got a little bit of progress, but it is frustration, by not using the environment variables passed through a file but just added the flags directly.
I went through an just used the entrypoint
into the image to see what was going on, but then gave up and tried the argument since those were clearly defined. That worked.
Now I have a connection error, and I am unclear on the database.
Another indexer said to start the indexer agent first and that instantiates the database....and gave me his environment variables which showed two different db names.
So I used that, but have a connection error.
At least I am not stuck on the mnemonic, but that is very annoying..