2022-11-18 18:19:09 +00:00
|
|
|
import base64
|
|
|
|
import json
|
|
|
|
import subprocess
|
2022-12-23 12:58:26 +00:00
|
|
|
import time
|
2022-11-18 18:19:09 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
import requests
|
|
|
|
from pystarport import ports
|
|
|
|
|
|
|
|
from .network import setup_custom_ethermint
|
|
|
|
from .utils import (
|
|
|
|
CONTRACTS,
|
|
|
|
decode_bech32,
|
|
|
|
deploy_contract,
|
|
|
|
supervisorctl,
|
2022-12-23 12:58:26 +00:00
|
|
|
wait_for_block,
|
2022-11-18 18:19:09 +00:00
|
|
|
wait_for_port,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
|
|
def custom_ethermint(tmp_path_factory):
|
|
|
|
path = tmp_path_factory.mktemp("grpc-only")
|
|
|
|
|
|
|
|
# reuse rollback-test config because it has an extra fullnode
|
|
|
|
yield from setup_custom_ethermint(
|
|
|
|
path,
|
|
|
|
26400,
|
|
|
|
Path(__file__).parent / "configs/rollback-test.jsonnet",
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def grpc_eth_call(port: int, args: dict, chain_id=None, proposer_address=None):
|
|
|
|
"""
|
|
|
|
do a eth_call through grpc gateway directly
|
|
|
|
"""
|
|
|
|
params = {
|
|
|
|
"args": base64.b64encode(json.dumps(args).encode()).decode(),
|
|
|
|
}
|
|
|
|
if chain_id is not None:
|
|
|
|
params["chain_id"] = str(chain_id)
|
|
|
|
if proposer_address is not None:
|
|
|
|
params["proposer_address"] = str(proposer_address)
|
|
|
|
return requests.get(
|
|
|
|
f"http://localhost:{port}/ethermint/evm/v1/eth_call", params
|
|
|
|
).json()
|
|
|
|
|
|
|
|
|
|
|
|
def test_grpc_mode(custom_ethermint):
|
|
|
|
"""
|
|
|
|
- restart a fullnode in grpc-only mode
|
|
|
|
- test the grpc queries all works
|
|
|
|
"""
|
|
|
|
w3 = custom_ethermint.w3
|
|
|
|
contract, _ = deploy_contract(w3, CONTRACTS["TestChainID"])
|
|
|
|
assert 9000 == contract.caller.currentChainID()
|
|
|
|
|
|
|
|
msg = {
|
|
|
|
"to": contract.address,
|
|
|
|
"data": contract.encodeABI(fn_name="currentChainID"),
|
|
|
|
}
|
2022-12-23 12:58:26 +00:00
|
|
|
api_port = ports.api_port(custom_ethermint.base_port(1))
|
2022-11-18 18:19:09 +00:00
|
|
|
# in normal mode, grpc query works even if we don't pass chain_id explicitly
|
2022-12-23 12:58:26 +00:00
|
|
|
success = False
|
|
|
|
max_retry = 3
|
|
|
|
sleep = 1
|
|
|
|
for i in range(max_retry):
|
|
|
|
rsp = grpc_eth_call(api_port, msg)
|
|
|
|
ret = rsp["ret"]
|
|
|
|
valid = ret is not None
|
|
|
|
if valid and 9000 == int.from_bytes(base64.b64decode(ret.encode()), "big"):
|
|
|
|
success = True
|
|
|
|
break
|
|
|
|
time.sleep(sleep)
|
|
|
|
assert success
|
|
|
|
# wait 1 more block for both nodes to avoid node stopped before tnx get included
|
|
|
|
for i in range(2):
|
|
|
|
wait_for_block(custom_ethermint.cosmos_cli(i), 1)
|
2022-11-18 18:19:09 +00:00
|
|
|
supervisorctl(
|
2022-12-23 12:58:26 +00:00
|
|
|
custom_ethermint.base_dir / "../tasks.ini", "stop", "ethermint_9000-1-node1"
|
2022-11-18 18:19:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# run grpc-only mode directly with existing chain state
|
2022-12-23 12:58:26 +00:00
|
|
|
with (custom_ethermint.base_dir / "node1.log").open("a") as logfile:
|
2022-11-18 18:19:09 +00:00
|
|
|
proc = subprocess.Popen(
|
|
|
|
[
|
|
|
|
"ethermintd",
|
|
|
|
"start",
|
|
|
|
"--grpc-only",
|
|
|
|
"--home",
|
2022-12-23 12:58:26 +00:00
|
|
|
custom_ethermint.base_dir / "node1",
|
2022-11-18 18:19:09 +00:00
|
|
|
],
|
|
|
|
stdout=logfile,
|
|
|
|
stderr=subprocess.STDOUT,
|
|
|
|
)
|
|
|
|
try:
|
|
|
|
# wait for grpc and rest api ports
|
2022-12-23 12:58:26 +00:00
|
|
|
grpc_port = ports.grpc_port(custom_ethermint.base_port(1))
|
2022-11-18 18:19:09 +00:00
|
|
|
wait_for_port(grpc_port)
|
|
|
|
wait_for_port(api_port)
|
|
|
|
|
|
|
|
# in grpc-only mode, grpc query don't work if we don't pass chain_id
|
|
|
|
rsp = grpc_eth_call(api_port, msg)
|
|
|
|
assert rsp["code"] != 0, str(rsp)
|
|
|
|
assert "invalid chain ID" in rsp["message"]
|
|
|
|
|
|
|
|
# it don't works without proposer address neither
|
|
|
|
rsp = grpc_eth_call(api_port, msg, chain_id=9000)
|
|
|
|
assert rsp["code"] != 0, str(rsp)
|
|
|
|
assert "validator does not exist" in rsp["message"]
|
|
|
|
|
|
|
|
# pass the first validator's consensus address to grpc query
|
2022-12-23 12:58:26 +00:00
|
|
|
addr = custom_ethermint.cosmos_cli(0).consensus_address()
|
|
|
|
cons_addr = decode_bech32(addr)
|
2022-11-18 18:19:09 +00:00
|
|
|
|
|
|
|
# should work with both chain_id and proposer_address set
|
|
|
|
rsp = grpc_eth_call(
|
|
|
|
api_port,
|
|
|
|
msg,
|
|
|
|
chain_id=100,
|
|
|
|
proposer_address=base64.b64encode(cons_addr).decode(),
|
|
|
|
)
|
|
|
|
assert "code" not in rsp, str(rsp)
|
|
|
|
assert 100 == int.from_bytes(base64.b64decode(rsp["ret"].encode()), "big")
|
|
|
|
finally:
|
|
|
|
proc.terminate()
|
|
|
|
proc.wait()
|