Skip to content
Open
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
194 changes: 194 additions & 0 deletions integration_tests/tests/cips/cip_145_fix_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import pytest
from typing import Type
from integration_tests.test_framework.test_framework import FrameworkOptions
from integration_tests.tests.conftest import ConfluxTestFramework
from cfx_utils import CFX
from conflux_web3 import Web3

STORAGE_COLLATERAL = 62500000000000000

class BaseTestEnv(ConfluxTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.conf_parameters["public_evm_rpc_apis"] = '"all"'
self.conf_parameters["executive_trace"] = "true"

def setup_network(self):
self.add_nodes(self.num_nodes)
self.start_node(0, ["--archive"])

class CIP145FixTestEnv(BaseTestEnv):
def set_test_params(self):
super().set_test_params()

class CIP145TestEnv(BaseTestEnv):
def set_test_params(self):
super().set_test_params()
# disable V3.0 hardfork (CIP-145-fix)
self.conf_parameters["eoa_code_transition_height"] = 99999999

class CIP78TestEnv(BaseTestEnv):
def set_test_params(self):
super().set_test_params()
# disable V2.4 hardfork(CIP-145)
self.conf_parameters["base_fee_burn_transition_number"] = 99999999
self.conf_parameters["base_fee_burn_transition_height"] = 99999999
# disable V3.0 hardfork (CIP-145-fix)
self.conf_parameters["eoa_code_transition_height"] = 99999999

class OriginTestEnv(BaseTestEnv):
def set_test_params(self):
super().set_test_params()
# disable CIP-78b
self.conf_parameters["cip78_patch_transition_number"] = 99999999
# disable V2.4 hardfork (CIP-145)
self.conf_parameters["base_fee_burn_transition_number"] = 99999999
self.conf_parameters["base_fee_burn_transition_height"] = 99999999
# disable V3.0 hardfork (CIP-145-fix)
self.conf_parameters["eoa_code_transition_height"] = 99999999


# copied from integration_tests/tests/conftest.py to overide fixture scope
@pytest.fixture
def network(framework_class: Type[ConfluxTestFramework], module_internal_port_min: int, additional_secrets: int, args: FrameworkOptions, request: pytest.FixtureRequest):
try:
framework = framework_class(module_internal_port_min, additional_secrets, options=args)
except Exception as e:
pytest.fail(f"Failed to setup framework: {e}")
yield framework
framework.teardown(request)

@pytest.fixture
def gas_sponsored_contract(network):
contract = network.deploy_contract("Receivable", {
"gasPrice": 1,
})
contract_address = contract.address
sponsor_whitelist_control = network.internal_contract("SponsorWhitelistControl")

# contract_addr, upperbound
sponsor_whitelist_control.functions.setSponsorForGas(contract_address, 10 ** 9).transact({
"value": CFX(1),
"gasPrice": 1,
}).executed()
sponsor_whitelist_control.functions.addPrivilegeByAdmin(contract_address, [network.cw3.address.zero_address()]).transact(
{
"gasPrice": 1,
}
).executed()
return contract

def fund_new_account(cw3: Web3, value: int):
account = cw3.cfx.account.create()
cw3.wallet.add_account(account)
cw3.cfx.send_transaction({
"value": value,
"to": account.address,
"gasPrice": 1
}).executed()
return account

def send_raw_failed_transaction_executed(network, raw_tx):
# with pytest.raises(Web3RPCError) as e:
# network.cw3.cfx.send_raw_transaction(raw_tx.raw_transaction)
# assert "is discarded due to out of balance" in e.value.message

latest_block = network.cw3.cfx.get_block("latest_mined")
new_block_hash = network.client.generate_custom_block(latest_block["hash"].to_0x_hex(), [], [raw_tx])
parent_block = new_block_hash
for _ in range(10):
parent_block = network.client.generate_block_with_parent(parent_block, num_txs=1)

transaction_hash = raw_tx.hash
return network.cw3.cfx.get_transaction_receipt(transaction_hash)

@pytest.mark.parametrize("framework_class", [OriginTestEnv, CIP78TestEnv, CIP145TestEnv, CIP145FixTestEnv])
def test_success_behaviour(network, gas_sponsored_contract):
network.client.generate_blocks_to_state()
cw3 = network.cw3
assert network.internal_contract("SponsorWhitelistControl").functions.isAllWhitelisted(gas_sponsored_contract.address).call()
sender = fund_new_account(cw3, STORAGE_COLLATERAL)

raw_tx = sender.sign_transaction({
"to": gas_sponsored_contract.address,
"value": 0,
"from": sender.address,
"chainId": network.cw3.cfx.chain_id,
"gas": 30000,
"gasPrice": 1,
"storageLimit": 64,
"epochHeight": 10,
"nonce": 0,
})
receipt = cw3.cfx.send_raw_transaction(raw_tx.raw_transaction).executed()
assert receipt["gasCoveredBySponsor"]

@pytest.mark.parametrize("framework_class,expected_sponsor_flag",
[(OriginTestEnv, False),
(CIP78TestEnv, True),
(CIP145TestEnv, True),
(CIP145FixTestEnv, False)])
def test_not_enough_balance_behaviour(network, gas_sponsored_contract, expected_sponsor_flag):
cw3 = network.cw3
# ensure hardfork transition number
network.client.generate_blocks_to_state()
assert network.internal_contract("SponsorWhitelistControl").functions.isAllWhitelisted(gas_sponsored_contract.address).call()
sender = fund_new_account(cw3, 50000)

before_balance = cw3.cfx.get_balance(sender.address)

raw_tx = sender.sign_transaction({
"to": gas_sponsored_contract.address,
"value": 0,
"from": sender.address,
"chainId": network.cw3.cfx.chain_id,
"gas": 30000,
"gasPrice": 1,
"storageLimit": 64,
"epochHeight": 10,
"nonce": 0,
})

receipt = send_raw_failed_transaction_executed(network, raw_tx)
after_balance = cw3.cfx.get_balance(sender.address)

# Gas is not covered by sponsor actually
assert after_balance < before_balance
assert "NotEnoughCash" in receipt["txExecErrorMsg"]
assert receipt["gasCoveredBySponsor"] == expected_sponsor_flag


@pytest.mark.parametrize("framework_class,expected_sponsor_flag",
[(OriginTestEnv, False),
(CIP78TestEnv, True),
(CIP145TestEnv, False),
(CIP145FixTestEnv, True)])
def test_out_of_gas_behaviour(network, gas_sponsored_contract, expected_sponsor_flag):
cw3 = network.cw3
# ensure hardfork transition number
network.client.generate_blocks_to_state()
assert network.internal_contract("SponsorWhitelistControl").functions.isAllWhitelisted(gas_sponsored_contract.address).call()

# Ensure sufficient funds so the transaction does not fail due to insufficient balance for storage collateral.
sender = fund_new_account(cw3, STORAGE_COLLATERAL + 50000)

before_balance = cw3.cfx.get_balance(sender.address)

raw_tx = sender.sign_transaction({
"to": gas_sponsored_contract.address,
"value": 0,
"from": sender.address,
"chainId": network.cw3.cfx.chain_id,
"gas": 22000,
"gasPrice": 1,
"storageLimit": 64,
"epochHeight": 10,
"nonce": 0,
})
receipt = send_raw_failed_transaction_executed(network, raw_tx)
after_balance = cw3.cfx.get_balance(sender.address)

# Gas is not covered by sponsor
assert after_balance == before_balance
assert "OutOfGas" in receipt["txExecErrorMsg"]
assert receipt["gasCoveredBySponsor"] == expected_sponsor_flag
17 changes: 17 additions & 0 deletions integration_tests/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
PORT_MIN = 11000
PORT_MAX = 65535
PORT_RANGE = 100
# if os.cpu_count() is not available, use 6 as default
MAX_WORKER_COUNT = os.cpu_count() or 6

# pytest hook to add options
def pytest_addoption(parser):
Expand Down Expand Up @@ -152,8 +154,23 @@ def network(framework_class: Type[ConfluxTestFramework], port_min: int, addition
def port_min(worker_id: str) -> int:
# worker_id is "master" or "gw0", "gw1", etc.
index = int(worker_id.split("gw")[1]) if "gw" in worker_id else 0
if index >= MAX_WORKER_COUNT:
raise ValueError(
f"You are using too pytest workers more than {MAX_WORKER_COUNT}. Please run `pytest integration_tests/tests -n <number> --dist loadscope` where <number> is less than {MAX_WORKER_COUNT}."
)
return PORT_MIN + index * PORT_RANGE

# in certain tests, we need to test
@pytest.fixture(scope="module")
def module_internal_port_min(worker_id: str) -> int:
# worker_id is "master" or "gw0", "gw1", etc.
index = int(worker_id.split("gw")[1]) if "gw" in worker_id else 0
if index >= MAX_WORKER_COUNT:
raise ValueError(
f"You are using too pytest workers more than {MAX_WORKER_COUNT}. Please run pytest w -n <number> where <number> is less than {MAX_WORKER_COUNT}."
)
return PORT_MIN + (index + MAX_WORKER_COUNT) * PORT_RANGE

@pytest.fixture(scope="module")
def additional_secrets():
return 0
Expand Down
22 changes: 16 additions & 6 deletions integration_tests/tests/rpc/espace/test_tx_and_receipt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest
from integration_tests.test_framework.test_framework import ConfluxTestFramework
from integration_tests.test_framework.util import *
from eth_utils import decode_hex
from integration_tests.test_framework.util import assert_equal
from integration_tests.conflux.rpc import RpcClient
from integration_tests.test_framework.blocktools import encode_hex_0x

Expand Down Expand Up @@ -31,18 +30,29 @@ def test_cross_space_transfer(cw3, ew3, erc20_contract, evm_accounts, network):
epoch = receipt["epochNumber"]
ret = network.nodes[0].debug_getTransactionsByEpoch(hex(epoch))
assert_equal(len(ret), 1)

def test_tx_and_receipt(ew3, evm_accounts, receiver_account, network):

@pytest.fixture(scope="module")
def tx_hash(ew3, evm_accounts, receiver_account):
account = evm_accounts[0]
nonce = ew3.eth.get_transaction_count(account.address)
tx_hash = ew3.eth.send_transaction({
"from": account.address,
"to": receiver_account.address,
"value": ew3.to_wei(1, "ether"),
"gasPrice": 1,
"gas": 21000,
"nonce": nonce,
})
ew3.eth.wait_for_transaction_receipt(tx_hash)
return tx_hash

def test_tx_data(ew3, tx_hash, receiver_account):
data = ew3.eth.get_transaction(tx_hash)
assert data["gasPrice"] == 1
assert data["gas"] == 21000
assert data["to"] == receiver_account.address
assert data["value"] == ew3.to_wei(1, "ether")


def test_tx_and_receipt(ew3, network, tx_hash):
receipt = ew3.eth.wait_for_transaction_receipt(tx_hash)
assert receipt["status"] == 1
assert receipt["gasUsed"] == 21000
Expand Down
Loading