[Ethereum] How to create a listener for new transaction with Ethereum RPC calls

filtersgo-ethereumjson-rpc

I am trying to create mini-service which would allow me to subscribe for incoming Ethereum transactions (coinbase example).

I thought that in Ethereum it could be done with eth_newFilter and eth_getFilterChanges (JSON RPC) methods but I am doing something wrong. Could you please give any clue or maybe I completely misunderstood the concept of the filters? I know that there is eth_newPendingTransactionFilter method, but I thought maybe there is a better way to achieve my goal? Right now I am following these steps:

Start geth

I know that I shouldn't open RPC like this, but right now I have done this for simplicity.

geth --dev --rpc --rpcapi "personal,miner,db,shh,admin,eth" --rpcaddr "localhost" --rpcport "8545"

Check accounts:

➜  curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params": [],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":[]}

Create two accounts:

➜  curl -X POST --data '{"jsonrpc":"2.0","method":"personal_newAccount","params":["password"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":"0x0199147554059ce1fa572600256dd6030db19658"}
➜  curl -X POST --data '{"jsonrpc":"2.0","method":"personal_newAccount","params":["password"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":"0x350060daba130bed0809126c67240d38f27c4cff"}

Start miner:

➜  curl -X POST --data '{"jsonrpc":"2.0","method":"miner_start","params":["1"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":true}

Create new filter:

➜  curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"address": "0x350060daba130bed0809126c67240d38f27c4cff", "fromBlock":"latest","toBlock":"latest"}],"id":2}' localhost:8545
{"id":2,"jsonrpc":"2.0","result":"0x0"}

Unlock account and send transaction:

➜  curl -X POST --data '{"jsonrpc":"2.0","method":"personal_unlockAccount","params":["0x0199147554059ce1fa572600256dd6030db19658","password"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":true}
➜  curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from": "0x0199147554059ce1fa572600256dd6030db19658","to": "0x350060daba130bed0809126c67240d38f27c4cff", "value":"0x1" }],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":"0xd0e910765a920b30fc2e70de6fc4557e74ad69c584d810f70188d254db7119bb"}

Wait for transaction proceed by local node:

➜ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x350060daba130bed0809126c67240d38f27c4cff"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":"0x01"}

Check filter and got nothing 🙁

➜ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getFilterChanges","params":["0x00"],"id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":[]}

Best Answer

Filters work a little bit different. Filters require LOGs to be emitted from an EVM execution (i.e. a contract). Solidity makes this easy for you by allowing you to fire events (compiled events generate LOGs).

Let's take the following contract:

contract T {
    event res(uint indexed out)
    function echo(uint in) {
         res(i);
    }
}

When the method echo is invoked on the contract it fires the solidity event res. These events can be caught using the eth_newFilter and queried using eth_getFilterChanges.

When creating a filter for a specific event (e.g. res) we need to derive the event signature first. Signatures are generated using the first 4 bytes of the keccak hash of the event's definition (i.e. res(uint)): keccak("res(uint)"). This then becomes the first argument for the eth_newFilter's topics.

Any of the arguments in the definition of the event that have the indexed keyword (as in the example contract listed above) can also be used to filter on. Let's say we only want to catch events for the number 6, we would then construct the following JSON-RPC:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_newFilter","params":[{"address": "0xaddress", topics:["KECCAK_HASH", "0x6"], "fromBlock":"latest","toBlock":"latest"}],"id":2}' localhost:8545 {"id":2,"jsonrpc":"2.0","result":"0x0"}

Now whenever the method echo(6) is invoked on the contract you'll be able to query the result using the eth_getFilterChanges.

Please see the solidity docs on events for more information.

Related Topic