Using light geth node with Metamask

Ditch INFURA as the middleman and go full decentralized

libertylocked
4 min readNov 12, 2017

The web3 middleman problem

By default Metamask uses INFURA as it’s RPC provider. Don’t get me wrong. INFURA is great (although it lacks some features). It’s damn fast, and makes it infinitely easier for web3 beginners. The way it’s set up in Metamask looks kind of like this:

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/metamask'));
// then try some requests
web3.eth.getBlockNumber(console.log);

You can try the above code yourself in Node.js. It basically tells web3 to use INFURA’s geth node to JSON-RPC on.

But now we have a trusted third party problem. Web3 JSON-RPCs INFURA’s nodes, and just trust whatever they reply to us. AFAIK there is no SPV built into web3.js, and the provider is the absolute source of truth.

You don’t want that in a decentralized world, do you?

Running a light geth node

We all know that you should run a full node if you want to go full decentralized. But not everyone can run a full node because it takes a really long time to sync, and it requires a lot of disk space.

Since geth 1.5.2, you can run geth in light client mode. Instead of reconstructing the entire chain state, light sync mode only gets the block headers. It takes minutes to sync, and only uses a few hundred MBs of disk. When you request information, your light geth node queries its peers.

The very important difference between RPC’ing a trusted node and RPC’ing a light node you run is this: even you’re still getting blockchain data from someone else, your light node does not trust the peers and will do all the verifications.

To start geth in light sync mode with 2048 MB cache, and with HTTP-RPC enabled on port 8545, simply run this command:

geth --syncmode light --cache 2048 --rpc --rpccorsdomain moz-extension://e582a415-cf54-468e-9b4b-f32b576f7bf7,chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn

The extension ID above may not be up to date — you can find it by popping out Metamask popup into a tab, or right click View Source and copy the extension ID from address bar.

The above command enables CORS for Metamask extension on Firefox and Chrome. If you only need one of them, feel free to remove the other.

It may take a few minutes to sync. Meanwhile you can run geth attach to attach to the IPC and check the sync progress.

$ geth attach ~/.ethereum/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.7.3-unstable-3ee86a57/linux-amd64/go1.9.2
modules: admin:1.0 debug:1.0 eth:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> eth.syncing
{
currentBlock: 1026432,
highestBlock: 4537745,
knownStates: 0,
pulledStates: 0,
startingBlock: 966336
}
> net.peerCount
8
> eth.blockNumber
1032576

Verify your HTTP-RPC works in Node.js

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
// then try some requests
web3.eth.getBlockNumber(console.log);

I’ve encountered a weird bug where my Geth node doesn’t open HTTP-RPC when running in light syncmode, even with --rpc flag on. If that happens to you, simply geth attach and type admin.startRPC() in your Geth JavaScript console.

Setting up Metamask to use your local geth

Very conveniently there’s an option to use localhost 8545 in Metamask

Setting Metamask to use local geth node running in light sync mode
  • If HTTP-RPC works in your Node.js environment but not Metamask, then your CORS domain setting is wrong. Restart geth with the correct --rpccorsdomain. See above
  • If HTTP-RPC does not work in Node.js or Metamask, and only IPC-RPC works, then your HTTP-RPC is probably not even turned on.

That’s it! Now enjoy the decentralized world where you rely on nobody but yourself.

Bonus: filters

Web3 comes with a very handy feature: filters. You can read the documentation on web3.eth.filter if you care. It basically lets you set up filters and watch for certain events. Very useful if you don’t want to constantly poll the state.

Unfortunately, INFURA does not support such call to create and watch filters.

Fun side node: Metamask by default constantly calls getBlockNumber on the geth node, INFURA or otherwise, when it could have used a filter to watch the latest block, which is far more performant. The reasoning is that, INFURA does not support filters, and Metamask by default uses INFURA as provider.

I’ve had the opportunity to talk to Michael Wuehler about INFURA at one of the meetups. He said filter is one of the most requested features. It’s not currently supported because it does not scale very well (or by his words, it’s linearly scaled).

It’s certainly a headache for DApp developers, because your filters won’t work in Firefox/Chrome with default Metamask settings. It works if user is using Metamask with a local geth node though.

--

--

libertylocked

📦 Ethereum web3 stack. Cryptographic systems. Privacy, anonymity, internet freedom. push32.com