Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Prune Node Integration Tests #1212

Merged
merged 22 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
go.sum
- uses: golangci/golangci-lint-action@v3
with:
version: latest
version: v1.48.0
args: --timeout 10m
github-token: ${{ secrets.github_token }}
# Check only if there are differences in the source code
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
PATTERNS: |
**/**.py
- run: |
nix-shell -I nixpkgs=./nix -p test-env --run "make lint-py"
nix-shell -I nixpkgs=./nix -p test-env --run "make lint-py"
if: env.GIT_DIFF
gomod2nix:
name: Check gomod2nix.toml file is up to date
Expand Down
3 changes: 2 additions & 1 deletion app/ante/doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*Package ante defines the SDK auth module's AnteHandler as well as an internal
/*
Package ante defines the SDK auth module's AnteHandler as well as an internal
AnteHandler for an Ethereum transaction (i.e MsgEthereumTx).
During CheckTx, the transaction is passed through a series of
Expand Down
2 changes: 1 addition & 1 deletion app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (app *EthermintApp) ExportAppStateAndValidators(

// prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature which will be deprecated
// in favor of export at a block height
// in favor of export at a block height
func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) error {
applyAllowedAddrs := false

Expand Down
2 changes: 1 addition & 1 deletion app/simulation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestAppImportExport(t *testing.T) {

fmt.Printf("importing genesis...\n")

// nolint: dogsled
//nolint: dogsled
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
require.NoError(t, err, "simulation setup failed")

Expand Down
14 changes: 8 additions & 6 deletions client/keys/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,16 @@ const (
mnemonicEntropySize = 256
)

/* RunAddCmd
/*
RunAddCmd
input
- bip39 mnemonic
- bip39 passphrase
- bip44 path
- local encryption password
- bip39 mnemonic
- bip39 passphrase
- bip44 path
- local encryption password

output
- armor encrypted private key (saved to file)
- armor encrypted private key (saved to file)
*/
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
var err error
Expand Down
2 changes: 1 addition & 1 deletion cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func SetBech32Prefixes(config *sdk.Config) {
func SetBip44CoinType(config *sdk.Config) {
config.SetCoinType(ethermint.Bip44CoinType)
config.SetPurpose(sdk.Purpose) // Shared
config.SetFullFundraiserPath(ethermint.BIP44HDPath) // nolint: staticcheck
config.SetFullFundraiserPath(ethermint.BIP44HDPath) //nolint: staticcheck
}

// RegisterDenoms registers the base and display denominations to the SDK.
Expand Down
2 changes: 1 addition & 1 deletion rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

// BackendI implements the Cosmos and EVM backend.
type BackendI interface { // nolint: revive
type BackendI interface { //nolint: revive
CosmosBackend
EVMBackend
}
Expand Down
2 changes: 1 addition & 1 deletion rpc/namespaces/ethereum/debug/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func (a *API) BlockProfile(file string, nsec uint) error {

// CpuProfile turns on CPU profiling for nsec seconds and writes
// profile data to file.
func (a *API) CpuProfile(file string, nsec uint) error { // nolint: golint, stylecheck, revive
func (a *API) CpuProfile(file string, nsec uint) error { //nolint: golint, stylecheck, revive
a.logger.Debug("debug_cpuProfile", "file", file, "nsec", nsec)
if err := a.StartCPUProfile(file); err != nil {
return err
Expand Down
7 changes: 6 additions & 1 deletion rpc/namespaces/ethereum/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
}

// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
func (e *PublicAPI) ChainId() (*hexutil.Big, error) { // nolint
func (e *PublicAPI) ChainId() (*hexutil.Big, error) { //nolint
e.logger.Debug("eth_chainId")
// if current block is at or past the EIP-155 replay-protection fork block, return chainID from config
bn, err := e.backend.BlockNumber()
Expand Down Expand Up @@ -294,6 +294,11 @@ func (e *PublicAPI) GetBalance(address common.Address, blockNrOrHash rpctypes.Bl
return nil, errors.New("invalid balance")
}

// balance can only be negative in case of pruned node
if val.IsNegative() {
return nil, errors.New("couldn't fetch balance. Node state is pruned")
}

return (*hexutil.Big)(val.BigInt()), nil
}

Expand Down
2 changes: 1 addition & 1 deletion rpc/namespaces/ethereum/eth/filters/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewRangeFilter(logger log.Logger, backend Backend, begin, end int64, addres
// Flatten the address and topic filter clauses into a single bloombits filter
// system. Since the bloombits are not positional, nil topics are permitted,
// which get flattened into a nil byte slice.
var filtersBz [][][]byte // nolint: prealloc
var filtersBz [][][]byte //nolint: prealloc
if len(addresses) > 0 {
filter := make([][]byte, len(addresses))
for i, address := range addresses {
Expand Down
6 changes: 3 additions & 3 deletions rpc/types/query_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
)

// QueryClient defines a gRPC Client used for:
// - Transaction simulation
// - EVM module queries
// - Fee market module queries
// - Transaction simulation
// - EVM module queries
// - Fee market module queries
type QueryClient struct {
tx.ServiceClient
evmtypes.QueryClient
Expand Down
9 changes: 9 additions & 0 deletions tests/integration_tests/.isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[settings]
# compatible with black
# https://black.readthedocs.io/en/stable/the_black_code_style.html
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88
12 changes: 12 additions & 0 deletions tests/integration_tests/configs/pruned_node.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
local config = import 'default.jsonnet';

config {
'ethermint_9000-1'+: {
'app-config'+: {
pruning: 'everything',
'state-sync'+: {
'snapshot-interval': 0,
},
},
},
}
142 changes: 142 additions & 0 deletions tests/integration_tests/test_pruned_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
from pathlib import Path

import pytest
from eth_bloom import BloomFilter
from eth_utils import abi, big_endian_to_int
from hexbytes import HexBytes
from web3.datastructures import AttributeDict

from .network import setup_custom_ethermint
from .utils import (
ADDRS,
CONTRACTS,
KEYS,
deploy_contract,
sign_transaction,
w3_wait_for_new_blocks,
)


@pytest.fixture(scope="module")
def pruned(request, tmp_path_factory):
"""start-cronos
params: enable_auto_deployment
"""
yield from setup_custom_ethermint(
tmp_path_factory.mktemp("pruned"),
26900,
Path(__file__).parent / "configs/pruned_node.jsonnet",
)


def test_pruned_node(pruned):
"""
test basic json-rpc apis works in pruned node
"""
w3 = pruned.w3
erc20 = deploy_contract(
w3,
CONTRACTS["TestERC20A"],
key=KEYS["validator"],
)
tx = erc20.functions.transfer(ADDRS["community"], 10).buildTransaction(
{"from": ADDRS["validator"]}
)
signed = sign_transaction(w3, tx, KEYS["validator"])
txhash = w3.eth.send_raw_transaction(signed.rawTransaction)
print("wait for prunning happens")
w3_wait_for_new_blocks(w3, 10)

tx_receipt = w3.eth.get_transaction_receipt(txhash.hex())
assert len(tx_receipt.logs) == 1
expect_log = {
"address": erc20.address,
"topics": [
HexBytes(
abi.event_signature_to_log_topic("Transfer(address,address,uint256)")
),
HexBytes(b"\x00" * 12 + HexBytes(ADDRS["validator"])),
HexBytes(b"\x00" * 12 + HexBytes(ADDRS["community"])),
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000a",
"transactionIndex": 0,
"logIndex": 0,
"removed": False,
}
assert expect_log.items() <= tx_receipt.logs[0].items()

# check get_balance and eth_call don't work on pruned state
# we need to check error message here.
# `get_balance` returns unmarshallJson and thats not what it should
facs95 marked this conversation as resolved.
Show resolved Hide resolved
facs95 marked this conversation as resolved.
Show resolved Hide resolved
res = w3.eth.get_balance(ADDRS["validator"], "latest")
assert res > 0

pruned_res = pruned.w3.provider.make_request(
"eth_getBalance", [ADDRS["validator"], hex(tx_receipt.blockNumber)]
)
assert "error" in pruned_res
assert (
pruned_res["error"]["message"] == "couldn't fetch balance. Node state is pruned"
)

with pytest.raises(Exception):
erc20.caller(block_identifier=tx_receipt.blockNumber).balanceOf(
ADDRS["validator"]
)

# check block bloom
block = w3.eth.get_block(tx_receipt.blockNumber)

assert "baseFeePerGas" in block
assert block.miner == "0x0000000000000000000000000000000000000000"
bloom = BloomFilter(big_endian_to_int(block.logsBloom))
assert HexBytes(erc20.address) in bloom
for topic in expect_log["topics"]:
assert topic in bloom

tx1 = w3.eth.get_transaction(txhash)
tx2 = w3.eth.get_transaction_by_block(
tx_receipt.blockNumber, tx_receipt.transactionIndex
)
exp_tx = AttributeDict(
{
"from": "0x57f96e6B86CdeFdB3d412547816a82E3E0EbF9D2",
"gas": 51542,
"input": (
"0xa9059cbb000000000000000000000000378c50d9264c63f3f92b806d4ee56e"
"9d86ffb3ec000000000000000000000000000000000000000000000000000000"
"000000000a"
),
"nonce": 2,
"to": erc20.address,
"transactionIndex": 0,
"value": 0,
"type": "0x2",
"accessList": [],
"chainId": "0x2328",
}
)
assert tx1 == tx2
for name in exp_tx.keys():
assert tx1[name] == tx2[name] == exp_tx[name]

logs = w3.eth.get_logs(
{
"fromBlock": tx_receipt.blockNumber,
"toBlock": tx_receipt.blockNumber,
}
)[0]
assert (
"address" in logs
and logs["address"] == "0x68542BD12B41F5D51D6282Ec7D91D7d0D78E4503"
)
assert "topics" in logs and len(logs["topics"]) == 3
assert logs["topics"][0] == HexBytes(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
)
assert logs["topics"][1] == HexBytes(
"0x00000000000000000000000057f96e6b86cdefdb3d412547816a82e3e0ebf9d2"
)
assert logs["topics"][2] == HexBytes(
"0x000000000000000000000000378c50d9264c63f3f92b806d4ee56e9d86ffb3ec"
)
ramacarlucho marked this conversation as resolved.
Show resolved Hide resolved
57 changes: 57 additions & 0 deletions tests/integration_tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
import json
import os
import socket
import time
from pathlib import Path

from dotenv import load_dotenv
from eth_account import Account
from web3._utils.transactions import fill_nonce, fill_transaction_defaults

load_dotenv(Path(__file__).parent.parent.parent / "scripts/.env")
Account.enable_unaudited_hdwallet_features()
ACCOUNTS = {
"validator": Account.from_mnemonic(os.getenv("VALIDATOR1_MNEMONIC")),
"community": Account.from_mnemonic(os.getenv("COMMUNITY_MNEMONIC")),
"signer1": Account.from_mnemonic(os.getenv("SIGNER1_MNEMONIC")),
"signer2": Account.from_mnemonic(os.getenv("SIGNER2_MNEMONIC")),
}
KEYS = {name: account.key for name, account in ACCOUNTS.items()}
ADDRS = {name: account.address for name, account in ACCOUNTS.items()}
ETHERMINT_ADDRESS_PREFIX = "ethm"
TEST_CONTRACTS = {
"TestERC20A": "TestERC20A.sol",
}


def contract_path(name, filename):
return (
Path(__file__).parent
/ "contracts/artifacts/contracts/"
/ filename
/ (name + ".json")
)


CONTRACTS = {
**{
name: contract_path(name, filename) for name, filename in TEST_CONTRACTS.items()
},
}

Account.enable_unaudited_hdwallet_features()

ACCOUNTS = {
Expand Down Expand Up @@ -32,6 +66,29 @@ def wait_for_port(port, host="127.0.0.1", timeout=40.0):
) from ex


def w3_wait_for_new_blocks(w3, n):
begin_height = w3.eth.block_number
while True:
time.sleep(0.5)
cur_height = w3.eth.block_number
if cur_height - begin_height >= n:
break


def deploy_contract(w3, jsonfile, args=(), key=KEYS["validator"]):
"""
deploy contract and return the deployed contract instance
"""
acct = Account.from_key(key)
info = json.loads(jsonfile.read_text())
contract = w3.eth.contract(abi=info["abi"], bytecode=info["bytecode"])
tx = contract.constructor(*args).buildTransaction({"from": acct.address})
txreceipt = send_transaction(w3, tx, key)
assert txreceipt.status == 1
address = txreceipt.contractAddress
return w3.eth.contract(address=address, abi=info["abi"])


def fill_defaults(w3, tx):
return fill_nonce(w3, fill_transaction_defaults(w3, tx))

Expand Down
9 changes: 7 additions & 2 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,13 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 {
// GetBalance load account's balance of gas token
func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int {
cosmosAddr := sdk.AccAddress(addr.Bytes())
params := k.GetParams(ctx)
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, params.EvmDenom)
evmDenom := ""
k.paramSpace.GetIfExists(ctx, types.ParamStoreKeyEVMDenom, &evmDenom)
// if node is pruned, params is empty. Return invalid value
if evmDenom == "" {
return big.NewInt(-1)
}
coin := k.bankKeeper.GetBalance(ctx, cosmosAddr, evmDenom)
return coin.Amount.BigInt()
}

Expand Down
Loading