tests(rpc): add filter tests (#1233)
* tests(rpc): add pending transaction filter test * tests(rpc): add block filter and event log test * tests(rpc): simplify to cluster instead of comparing types * tests(rpc): wip filter by address * tests(rpc): add get_logs test * fix flake8 linter * fix flake8 linter * add caching to readme * add caching to readme Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
94cab52ca1
commit
9bbf356c6b
@ -25,13 +25,13 @@ import (
|
|||||||
|
|
||||||
// FilterAPI gathers
|
// FilterAPI gathers
|
||||||
type FilterAPI interface {
|
type FilterAPI interface {
|
||||||
GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*ethtypes.Log, error)
|
NewPendingTransactionFilter() rpc.ID
|
||||||
GetFilterChanges(id rpc.ID) (interface{}, error)
|
|
||||||
GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ethtypes.Log, error)
|
|
||||||
NewBlockFilter() rpc.ID
|
NewBlockFilter() rpc.ID
|
||||||
NewFilter(criteria filters.FilterCriteria) (rpc.ID, error)
|
NewFilter(criteria filters.FilterCriteria) (rpc.ID, error)
|
||||||
NewPendingTransactionFilter() rpc.ID
|
GetFilterChanges(id rpc.ID) (interface{}, error)
|
||||||
|
GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ethtypes.Log, error)
|
||||||
UninstallFilter(id rpc.ID) bool
|
UninstallFilter(id rpc.ID) bool
|
||||||
|
GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*ethtypes.Log, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backend defines the methods requided by the PublicFilterAPI backend
|
// Backend defines the methods requided by the PublicFilterAPI backend
|
||||||
|
55
tests/integration_tests/README.md
Normal file
55
tests/integration_tests/README.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# RPC Integration tests
|
||||||
|
|
||||||
|
The RPC integration test suite uses nix for reproducible and configurable
|
||||||
|
builds allowing to run integration tests using python web3 library against
|
||||||
|
different Ethermint and [Geth](https://github.com/ethereum/go-ethereum) clients with multiple configurations.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Nix Multi-user installation:
|
||||||
|
|
||||||
|
```
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure the following line has been added to your shell profile (e.g. ~/.profile):
|
||||||
|
|
||||||
|
```
|
||||||
|
source ~/.nix-profile/etc/profile.d/nix.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then re-login shell, the nix installation is completed.
|
||||||
|
|
||||||
|
For linux:
|
||||||
|
|
||||||
|
```
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --no-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run Local
|
||||||
|
|
||||||
|
First time run (can take a while):
|
||||||
|
|
||||||
|
```
|
||||||
|
make run-integration-tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you've run them once and, you can run:
|
||||||
|
|
||||||
|
```
|
||||||
|
nix-shell tests/integration_tests/shell.nix
|
||||||
|
cd tests/integration_tests
|
||||||
|
pytest -s -vv
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're changing anything on the ethermint rpc, rerun the first command.
|
||||||
|
|
||||||
|
|
||||||
|
## Caching
|
||||||
|
|
||||||
|
You can enable Binary Cache to speed up the tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nix-env -iA cachix -f https://cachix.org/api/v1/install
|
||||||
|
$ cachix use ethermint
|
||||||
|
```
|
20
tests/integration_tests/contracts/contracts/Greeter.sol
Normal file
20
tests/integration_tests/contracts/contracts/Greeter.sol
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
pragma solidity >0.5.0;
|
||||||
|
|
||||||
|
contract Greeter {
|
||||||
|
string public greeting;
|
||||||
|
|
||||||
|
event ChangeGreeting(address from, string value);
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
greeting = "Hello";
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGreeting(string memory _greeting) public {
|
||||||
|
greeting = _greeting;
|
||||||
|
emit ChangeGreeting(msg.sender, _greeting);
|
||||||
|
}
|
||||||
|
|
||||||
|
function greet() public view returns (string memory) {
|
||||||
|
return greeting;
|
||||||
|
}
|
||||||
|
}
|
118
tests/integration_tests/test_filters.py
Normal file
118
tests/integration_tests/test_filters.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import pytest
|
||||||
|
from web3 import Web3
|
||||||
|
|
||||||
|
from .utils import (
|
||||||
|
ADDRS,
|
||||||
|
CONTRACTS,
|
||||||
|
deploy_contract,
|
||||||
|
send_successful_transaction,
|
||||||
|
send_transaction,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pending_transaction_filter(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
flt = w3.eth.filter("pending")
|
||||||
|
|
||||||
|
# without tx
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
txhash = send_successful_transaction(w3)
|
||||||
|
assert txhash in flt.get_new_entries()
|
||||||
|
|
||||||
|
# without new txs since last call
|
||||||
|
assert flt.get_new_entries() == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_block_filter(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
flt = w3.eth.filter("latest")
|
||||||
|
|
||||||
|
# without tx
|
||||||
|
assert flt.get_new_entries() == []
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
send_successful_transaction(w3)
|
||||||
|
blocks = flt.get_new_entries()
|
||||||
|
assert len(blocks) >= 1
|
||||||
|
|
||||||
|
# without new txs since last call
|
||||||
|
assert flt.get_new_entries() == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_log_filter_by_contract(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
contract = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
|
||||||
|
# Create new filter from contract
|
||||||
|
current_height = hex(w3.eth.get_block_number())
|
||||||
|
flt = contract.events.ChangeGreeting.createFilter(fromBlock=current_height)
|
||||||
|
|
||||||
|
# without tx
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
assert flt.get_all_entries() == [] # GetFilterLogs
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
tx = contract.functions.setGreeting("world").buildTransaction()
|
||||||
|
tx_receipt = send_transaction(w3, tx)
|
||||||
|
assert tx_receipt.status == 1
|
||||||
|
|
||||||
|
log = contract.events.ChangeGreeting().processReceipt(tx_receipt)[0]
|
||||||
|
assert log["event"] == "ChangeGreeting"
|
||||||
|
|
||||||
|
new_entries = flt.get_new_entries()
|
||||||
|
assert len(new_entries) == 1
|
||||||
|
assert new_entries[0] == log
|
||||||
|
assert contract.caller.greet() == "world"
|
||||||
|
|
||||||
|
# without new txs since last call
|
||||||
|
assert flt.get_new_entries() == []
|
||||||
|
assert flt.get_all_entries() == new_entries
|
||||||
|
|
||||||
|
# Uninstall
|
||||||
|
assert w3.eth.uninstall_filter(flt.filter_id)
|
||||||
|
assert not w3.eth.uninstall_filter(flt.filter_id)
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
flt.get_all_entries()
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_log_filter_by_address(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
|
contract = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
|
||||||
|
flt = w3.eth.filter({"address": contract.address})
|
||||||
|
flt2 = w3.eth.filter({"address": ADDRS["validator"]})
|
||||||
|
|
||||||
|
# without tx
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
assert flt.get_all_entries() == [] # GetFilterLogs
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
tx = contract.functions.setGreeting("world").buildTransaction()
|
||||||
|
receipt = send_transaction(w3, tx)
|
||||||
|
assert receipt.status == 1
|
||||||
|
|
||||||
|
assert len(flt.get_new_entries()) == 1
|
||||||
|
assert len(flt2.get_new_entries()) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_logs(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
|
contract = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
|
||||||
|
# without tx
|
||||||
|
assert w3.eth.get_logs({"address": contract.address}) == []
|
||||||
|
assert w3.eth.get_logs({"address": ADDRS["validator"]}) == []
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
tx = contract.functions.setGreeting("world").buildTransaction()
|
||||||
|
receipt = send_transaction(w3, tx)
|
||||||
|
assert receipt.status == 1
|
||||||
|
|
||||||
|
assert len(w3.eth.get_logs({"address": contract.address})) == 1
|
||||||
|
assert len(w3.eth.get_logs({"address": ADDRS["validator"]})) == 0
|
@ -24,6 +24,7 @@ ADDRS = {name: account.address for name, account in ACCOUNTS.items()}
|
|||||||
ETHERMINT_ADDRESS_PREFIX = "ethm"
|
ETHERMINT_ADDRESS_PREFIX = "ethm"
|
||||||
TEST_CONTRACTS = {
|
TEST_CONTRACTS = {
|
||||||
"TestERC20A": "TestERC20A.sol",
|
"TestERC20A": "TestERC20A.sol",
|
||||||
|
"Greeter": "Greeter.sol",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,6 +141,14 @@ def send_transaction(w3, tx, key=KEYS["validator"]):
|
|||||||
return w3.eth.wait_for_transaction_receipt(txhash)
|
return w3.eth.wait_for_transaction_receipt(txhash)
|
||||||
|
|
||||||
|
|
||||||
|
def send_successful_transaction(w3):
|
||||||
|
signed = sign_transaction(w3, {"to": ADDRS["community"], "value": 1000})
|
||||||
|
txhash = w3.eth.send_raw_transaction(signed.rawTransaction)
|
||||||
|
receipt = w3.eth.wait_for_transaction_receipt(txhash)
|
||||||
|
assert receipt.status == 1
|
||||||
|
return txhash
|
||||||
|
|
||||||
|
|
||||||
def eth_to_bech32(addr, prefix=ETHERMINT_ADDRESS_PREFIX):
|
def eth_to_bech32(addr, prefix=ETHERMINT_ADDRESS_PREFIX):
|
||||||
bz = bech32.convertbits(HexBytes(addr), 8, 5)
|
bz = bech32.convertbits(HexBytes(addr), 8, 5)
|
||||||
return bech32.bech32_encode(prefix, bz)
|
return bech32.bech32_encode(prefix, bz)
|
||||||
|
Loading…
Reference in New Issue
Block a user