Skip to content

Commit

Permalink
Problem: feegrant is not tested (fixes #614) #625
Browse files Browse the repository at this point in the history
Solution:
Add following tests to test tx feegrant grant and tx feegrant revoke

check whether granter pays transaction fee with no fee limit or grant expiry
check transaction should fail when exceeding grant fee limit
check transaction should fail after grant expiry date
check whether granter pays transaction fee under period limit during each period
check exceeding period limit should not affect the next period
check transaction should fail if fee grant is revoked
Fix #614
  • Loading branch information
macong-cdc authored Aug 17, 2021
1 parent 9deabbe commit 094b22c
Show file tree
Hide file tree
Showing 2 changed files with 337 additions and 0 deletions.
270 changes: 270 additions & 0 deletions integration_tests/test_feegrant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
import datetime
from time import sleep

import pytest

from .utils import (
BASECRO_DENOM,
SUCCESS_CODE,
grant_fee_allowance,
revoke_fee_grant,
transfer,
)

pytestmark = pytest.mark.normal


def test_basic_fee_allowance(cluster):
"""
check basic fee allowance with no limit or grant expiry
"""
transaction_coins = 100
fee_coins = 10

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

fee_granter_balance = cluster.balance(fee_granter_address)
fee_grantee_balance = cluster.balance(fee_grantee_address)
receiver_balance = cluster.balance(receiver_address)

grant_fee_allowance(cluster, fee_granter_address, fee_grantee_address)

transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)

assert cluster.balance(fee_granter_address) == fee_granter_balance - fee_coins
assert (
cluster.balance(fee_grantee_address) == fee_grantee_balance - transaction_coins
)
assert cluster.balance(receiver_address) == receiver_balance + transaction_coins


def test_tx_failed_when_exceeds_grant_fee(cluster):
"""
check transaction should fail when tx fee exceeds fee limit in basic fee allowance
"""
transaction_coins = 100
fee_coins = 10
fee_grant_spend_limit = 5

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

fee_granter_balance = cluster.balance(fee_granter_address)
fee_grantee_balance = cluster.balance(fee_grantee_address)
receiver_balance = cluster.balance(receiver_address)

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)
grant_fee_allowance(
cluster,
fee_granter_address,
fee_grantee_address,
spend_limit="%s%s" % (fee_grant_spend_limit, BASECRO_DENOM),
)

tx = transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)
assert tx["code"] != SUCCESS_CODE, "should fail as fee limit exceeded"

assert cluster.balance(fee_granter_address) == fee_granter_balance
assert cluster.balance(fee_grantee_address) == fee_grantee_balance
assert cluster.balance(receiver_address) == receiver_balance


def test_tx_failed_after_grant_expiration(cluster):
"""
check transaction should fail when tx happens after grant expiry
"""
transaction_coins = 100
fee_coins = 10

# RFC 3339 timestamp
grant_expiration = datetime.datetime.utcnow().isoformat() + "Z"

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

fee_granter_balance = cluster.balance(fee_granter_address)
fee_grantee_balance = cluster.balance(fee_grantee_address)
receiver_balance = cluster.balance(receiver_address)

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)
grant_fee_allowance(
cluster, fee_granter_address, fee_grantee_address, expiration=grant_expiration
)

tx = transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)
assert tx["code"] != SUCCESS_CODE, "should fail as fee allowance expired"

assert cluster.balance(fee_granter_address) == fee_granter_balance
assert cluster.balance(fee_grantee_address) == fee_grantee_balance
assert cluster.balance(receiver_address) == receiver_balance


def test_periodic_fee_allowance(cluster):
"""
check periodic fee allowance with no expiration
"""
transaction_coins = 100
fee_coins = 10

period = 5
period_limit = 11
number_of_periods = 3

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

fee_granter_balance = cluster.balance(fee_granter_address)
fee_grantee_balance = cluster.balance(fee_grantee_address)
receiver_balance = cluster.balance(receiver_address)

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)
grant_fee_allowance(
cluster,
fee_granter_address,
fee_grantee_address,
period_limit="%s%s" % (period_limit, BASECRO_DENOM),
period=period,
)

for _ in range(number_of_periods):
transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)
sleep(period)

assert (
cluster.balance(fee_granter_address)
== fee_granter_balance - fee_coins * number_of_periods
)
assert (
cluster.balance(fee_grantee_address)
== fee_grantee_balance - transaction_coins * number_of_periods
)
assert (
cluster.balance(receiver_address)
== receiver_balance + transaction_coins * number_of_periods
)


def test_exceed_period_limit_should_not_affect_the_next_period(cluster):
"""
check exceeding periodic fee should not affect next period
"""
transaction_coins = 100
fee_coins = 10

period = 5
period_limit = 11

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

fee_granter_balance = cluster.balance(fee_granter_address)
fee_grantee_balance = cluster.balance(fee_grantee_address)
receiver_balance = cluster.balance(receiver_address)

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)
grant_fee_allowance(
cluster,
fee_granter_address,
fee_grantee_address,
period_limit="%s%s" % (period_limit, BASECRO_DENOM),
period=period,
)

transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)

failed_tx = transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)
assert failed_tx["code"] != SUCCESS_CODE, "should fail as fee exceeds period limit"
sleep(period)

transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)

# transaction only happened two times
assert cluster.balance(fee_granter_address) == fee_granter_balance - fee_coins * 2
assert (
cluster.balance(fee_grantee_address)
== fee_grantee_balance - transaction_coins * 2
)
assert cluster.balance(receiver_address) == receiver_balance + transaction_coins * 2


def test_revoke_fee_grant(cluster):
"""
check tx should fail after fee grant is revoked
"""
transaction_coins = 100
fee_coins = 10

fee_granter_address = cluster.address("community")
fee_grantee_address = cluster.address("ecosystem")
receiver_address = cluster.address("reserve")

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)
grant_fee_allowance(cluster, fee_granter_address, fee_grantee_address)

revoke_fee_grant(cluster, fee_granter_address, fee_grantee_address)

failed_tx = transfer(
cluster,
fee_grantee_address,
receiver_address,
"%s%s" % (transaction_coins, BASECRO_DENOM),
fees="%s%s" % (fee_coins, BASECRO_DENOM),
fee_account=fee_granter_address,
)

assert failed_tx["code"] != SUCCESS_CODE, "should fail as grant is revoked"
67 changes: 67 additions & 0 deletions integration_tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
from pystarport import cluster, ledger
from pystarport.ports import rpc_port

#################
# CONSTANTS
# Reponse code
SUCCESS_CODE = 0

# Denomination
CRO_DENOM = "cro"
BASECRO_DENOM = "basecro"


def wait_for_block(cli, height, timeout=240):
for i in range(timeout * 2):
Expand Down Expand Up @@ -202,3 +211,61 @@ def find_balance(balances, denom):
if balance["denom"] == denom:
return int(balance["amount"])
return 0


def transfer(cli, from_, to, coins, i=0, *k_options, **kv_options):
return json.loads(
cli.cosmos_cli(i).raw(
"tx",
"bank",
"send",
from_,
to,
coins,
"-y",
home=cli.cosmos_cli(i).data_dir,
keyring_backend="test",
chain_id=cli.cosmos_cli(i).chain_id,
node=cli.cosmos_cli(i).node_rpc,
*k_options,
**kv_options,
)
)


def grant_fee_allowance(cli, granter_address, grantee, i=0, *k_options, **kv_options):
return json.loads(
cli.cosmos_cli(i).raw(
"tx",
"feegrant",
"grant",
granter_address,
grantee,
"-y",
home=cli.cosmos_cli(i).data_dir,
keyring_backend="test",
chain_id=cli.cosmos_cli(i).chain_id,
node=cli.cosmos_cli(i).node_rpc,
*k_options,
**kv_options,
)
)


def revoke_fee_grant(cli, granter_address, grantee, i=0, *k_options, **kv_options):
return json.loads(
cli.cosmos_cli(i).raw(
"tx",
"feegrant",
"revoke",
granter_address,
grantee,
"-y",
home=cli.cosmos_cli(i).data_dir,
keyring_backend="test",
chain_id=cli.cosmos_cli(i).chain_id,
node=cli.cosmos_cli(i).node_rpc,
*k_options,
**kv_options,
)
)

0 comments on commit 094b22c

Please sign in to comment.