upgrade to ethermint v0.21.0 #99
@ -20,8 +20,8 @@ schema = 3
|
|||||||
version = "v1.0.0-beta.7"
|
version = "v1.0.0-beta.7"
|
||||||
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
|
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
|
||||||
[mod."cosmossdk.io/math"]
|
[mod."cosmossdk.io/math"]
|
||||||
version = "v1.0.0-beta.3"
|
version = "v1.0.0-beta.4"
|
||||||
hash = "sha256-lTQ27ZlL+kWlc+S//sJmyiOwaf9qS+YLv61I4OXi9XE="
|
hash = "sha256-UYdq/46EubyjxkldGike8FlwJLWGCB576VB7th285ao="
|
||||||
[mod."filippo.io/edwards25519"]
|
[mod."filippo.io/edwards25519"]
|
||||||
version = "v1.0.0-rc.1"
|
version = "v1.0.0-rc.1"
|
||||||
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
|
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
|
||||||
|
@ -6,7 +6,7 @@ cd "$(dirname "$0")"
|
|||||||
export TMPDIR=/tmp
|
export TMPDIR=/tmp
|
||||||
|
|
||||||
echo "build test contracts"
|
echo "build test contracts"
|
||||||
cd ../tests/integration_tests/contracts
|
cd ../tests/integration_tests/hardhat
|
||||||
HUSKY_SKIP_INSTALL=1 npm install
|
HUSKY_SKIP_INSTALL=1 npm install
|
||||||
npm run typechain
|
npm run typechain
|
||||||
cd ..
|
cd ..
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
pragma solidity 0.8.10;
|
|
||||||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
||||||
|
|
||||||
contract TestERC20A is ERC20 {
|
|
||||||
|
|
||||||
constructor() public ERC20("TestERC20", "Test") {
|
|
||||||
_mint(msg.sender, 100000000000000000000000000);
|
|
||||||
}
|
|
||||||
}
|
|
25
tests/integration_tests/hardhat/contracts/Mars.sol
Normal file
25
tests/integration_tests/hardhat/contracts/Mars.sol
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.10;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||||
|
|
||||||
|
contract Mars is Initializable, ERC20Upgradeable, UUPSUpgradeable, OwnableUpgradeable {
|
||||||
|
function initialize() public initializer {
|
||||||
|
__ERC20_init("Mars", "MRS");
|
||||||
|
__Ownable_init();
|
||||||
|
_mint(msg.sender, 1000000 * 10 ** decimals());
|
||||||
|
}
|
||||||
|
|
||||||
|
function _authorizeUpgrade(address newImplementation) internal
|
||||||
|
override
|
||||||
|
onlyOwner {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract MarsV2 is Mars {
|
||||||
|
function version() pure public returns (string memory) {
|
||||||
|
return "v2";
|
||||||
|
}
|
||||||
|
}
|
10
tests/integration_tests/hardhat/contracts/TestERC20A.sol
Normal file
10
tests/integration_tests/hardhat/contracts/TestERC20A.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.10;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||||
|
|
||||||
|
contract TestERC20A is ERC20 {
|
||||||
|
constructor() public ERC20("TestERC20", "Test") {
|
||||||
|
_mint(msg.sender, 100000000000000000000000000);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
import { HardhatUserConfig } from "hardhat/config";
|
import type { HardhatUserConfig } from "hardhat/config";
|
||||||
import "hardhat-typechain";
|
import "hardhat-typechain";
|
||||||
|
import "@openzeppelin/hardhat-upgrades";
|
||||||
|
import "@nomiclabs/hardhat-ethers";
|
||||||
|
|
||||||
const config: HardhatUserConfig = {
|
const config: HardhatUserConfig = {
|
||||||
solidity: {
|
solidity: {
|
File diff suppressed because it is too large
Load Diff
@ -10,9 +10,11 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nomiclabs/hardhat-ethers": "^2.1.0",
|
|
||||||
"@nomiclabs/hardhat-waffle": "^2.0.3",
|
"@nomiclabs/hardhat-waffle": "^2.0.3",
|
||||||
"@openzeppelin/contracts": "^4.7.0",
|
"@openzeppelin/contracts": "^4.8.0",
|
||||||
|
"@nomiclabs/hardhat-ethers": "^2.2.1",
|
||||||
|
"@openzeppelin/hardhat-upgrades": "^1.21.0",
|
||||||
|
"@openzeppelin/contracts-upgradeable": "^4.3.1",
|
||||||
"@typechain/ethers-v5": "^5.0.0",
|
"@typechain/ethers-v5": "^5.0.0",
|
||||||
"hardhat": "^2.10.1",
|
"hardhat": "^2.10.1",
|
||||||
"hardhat-typechain": "^0.3.5",
|
"hardhat-typechain": "^0.3.5",
|
@ -1,4 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from eth_abi import abi
|
||||||
|
from hexbytes import HexBytes
|
||||||
from web3 import Web3
|
from web3 import Web3
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@ -9,6 +11,15 @@ from .utils import (
|
|||||||
send_transaction,
|
send_transaction,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Smart contract names
|
||||||
|
GREETER_CONTRACT = "Greeter"
|
||||||
|
ERC20_CONTRACT = "TestERC20A"
|
||||||
|
|
||||||
|
# ChangeGreeting topic from Greeter contract calculated from event signature
|
||||||
|
CHANGE_GREETING_TOPIC = Web3.keccak(text="ChangeGreeting(address,string)")
|
||||||
|
# ERC-20 Transfer event topic
|
||||||
|
TRANSFER_TOPIC = Web3.keccak(text="Transfer(address,address,uint256)")
|
||||||
|
|
||||||
|
|
||||||
def test_pending_transaction_filter(cluster):
|
def test_pending_transaction_filter(cluster):
|
||||||
|
|||||||
w3: Web3 = cluster.w3
|
w3: Web3 = cluster.w3
|
||||||
@ -65,7 +76,9 @@ def test_event_log_filter_by_contract(cluster):
|
|||||||
assert flt.get_all_entries() == [] # GetFilterLogs
|
assert flt.get_all_entries() == [] # GetFilterLogs
|
||||||
|
|
||||||
# with tx
|
# with tx
|
||||||
tx = contract.functions.setGreeting("world").build_transaction()
|
tx = contract.functions.setGreeting("world").build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
tx_receipt = send_transaction(w3, tx)
|
tx_receipt = send_transaction(w3, tx)
|
||||||
assert tx_receipt.status == 1
|
assert tx_receipt.status == 1
|
||||||
|
|
||||||
@ -102,7 +115,9 @@ def test_event_log_filter_by_address(cluster):
|
|||||||
assert flt.get_all_entries() == [] # GetFilterLogs
|
assert flt.get_all_entries() == [] # GetFilterLogs
|
||||||
|
|
||||||
# with tx
|
# with tx
|
||||||
tx = contract.functions.setGreeting("world").build_transaction()
|
tx = contract.functions.setGreeting("world").build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
receipt = send_transaction(w3, tx)
|
receipt = send_transaction(w3, tx)
|
||||||
assert receipt.status == 1
|
assert receipt.status == 1
|
||||||
|
|
||||||
@ -110,19 +125,565 @@ def test_event_log_filter_by_address(cluster):
|
|||||||
assert len(flt2.get_new_entries()) == 0
|
assert len(flt2.get_new_entries()) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_get_logs(cluster):
|
def test_event_log_filter_by_topic(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
|
new_greeting = "world"
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
{
|
||||||
|
"name": "one contract emiting one topic",
|
||||||
|
"filters": [
|
||||||
|
{"topics": [CHANGE_GREETING_TOPIC.hex()]},
|
||||||
|
{
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [CHANGE_GREETING_TOPIC.hex()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"exp_len": 1,
|
||||||
|
"exp_topics": [[CHANGE_GREETING_TOPIC]],
|
||||||
|
"contracts": [GREETER_CONTRACT],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "multiple contracts emitting same topic",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"topics": [CHANGE_GREETING_TOPIC.hex()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [CHANGE_GREETING_TOPIC.hex()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"exp_len": 5,
|
||||||
|
"exp_topics": [[CHANGE_GREETING_TOPIC]],
|
||||||
|
"contracts": [GREETER_CONTRACT] * 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "multiple contracts emitting different topics",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"topics": [[CHANGE_GREETING_TOPIC.hex(), TRANSFER_TOPIC.hex()]],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [[CHANGE_GREETING_TOPIC.hex(), TRANSFER_TOPIC.hex()]],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"exp_len": 3, # 2 transfer events, mint&transfer on deploy (2)tx in test
|
||||||
|
"exp_topics": [
|
||||||
|
[CHANGE_GREETING_TOPIC],
|
||||||
|
[
|
||||||
|
TRANSFER_TOPIC,
|
||||||
|
HexBytes(pad_left("0x0")),
|
||||||
|
HexBytes(pad_left(ADDRS["validator"].lower())),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
TRANSFER_TOPIC,
|
||||||
|
HexBytes(pad_left(ADDRS["validator"].lower())),
|
||||||
|
HexBytes(pad_left(ADDRS["community"].lower())),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"contracts": [GREETER_CONTRACT, ERC20_CONTRACT],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for tc in test_cases:
|
||||||
|
print("\nCase: {}".format(tc["name"]))
|
||||||
|
|
||||||
|
# register filters
|
||||||
|
filters = []
|
||||||
|
for fltr in tc["filters"]:
|
||||||
|
filters.append(w3.eth.filter(fltr))
|
||||||
|
|
||||||
|
# without tx: filters should not return any entries
|
||||||
|
for flt in filters:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
|
||||||
|
# deploy all contracts
|
||||||
|
# perform tx that emits event in all contracts
|
||||||
|
for c in tc["contracts"]:
|
||||||
|
tx = None
|
||||||
|
if c == GREETER_CONTRACT:
|
||||||
|
contract, _ = deploy_contract(w3, CONTRACTS[c])
|
||||||
|
# validate deploy was successfull
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
# create tx that emits event
|
||||||
|
tx = contract.functions.setGreeting(new_greeting).build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
|
elif c == ERC20_CONTRACT:
|
||||||
|
contract, _ = deploy_contract(w3, CONTRACTS[c])
|
||||||
|
# validate deploy was successfull
|
||||||
|
assert contract.caller.name() == "TestERC20"
|
||||||
|
# create tx that emits event
|
||||||
|
tx = contract.functions.transfer(
|
||||||
|
ADDRS["community"], 10
|
||||||
|
).build_transaction({"from": ADDRS["validator"]})
|
||||||
|
|
||||||
|
receipt = send_transaction(w3, tx)
|
||||||
|
assert receipt.status == 1
|
||||||
|
|
||||||
|
# check filters new entries
|
||||||
|
for flt in filters:
|
||||||
|
new_entries = flt.get_new_entries() # GetFilterChanges
|
||||||
|
assert len(new_entries) == tc["exp_len"]
|
||||||
|
|
||||||
|
for log in new_entries:
|
||||||
|
# check if the new_entries have valid information
|
||||||
|
assert log["topics"] in tc["exp_topics"]
|
||||||
|
assert_log_block(w3, log)
|
||||||
|
|
||||||
|
# on next call of GetFilterChanges, no entries should be found
|
||||||
|
# because there were no new logs that meet the filters params
|
||||||
|
for flt in filters:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
w3.eth.uninstall_filter(flt.filter_id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_filters(cluster):
|
||||||
w3: Web3 = cluster.w3
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
contract, _ = deploy_contract(w3, CONTRACTS["Greeter"])
|
contract, _ = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
# test the contract was deployed successfully
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
|
||||||
# without tx
|
new_greeting = "hello, world"
|
||||||
|
|
||||||
|
# calculate topic from event signature
|
||||||
|
topic = CHANGE_GREETING_TOPIC
|
||||||
|
# another topic not related to the contract deployed
|
||||||
|
another_topic = TRANSFER_TOPIC
|
||||||
|
|
||||||
|
filters = [
|
||||||
|
{
|
||||||
|
"params": {"address": contract.address},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {"topics": [topic.hex()]},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"topics": [
|
||||||
|
topic.hex(),
|
||||||
|
another_topic.hex(),
|
||||||
|
], # 'with all topics' condition
|
||||||
|
},
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"topics": [
|
||||||
|
[topic.hex(), another_topic.hex()]
|
||||||
|
], # 'with any topic' condition
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"address": contract.address,
|
||||||
|
"topics": [[topic.hex(), another_topic.hex()]],
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": 2,
|
||||||
|
"address": contract.address,
|
||||||
|
"topics": [[topic.hex(), another_topic.hex()]],
|
||||||
|
},
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"address": contract.address,
|
||||||
|
"topics": [[topic.hex(), another_topic.hex()]],
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [[topic.hex(), another_topic.hex()]],
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
{"name": "register multiple filters and check for updates", "filters": filters},
|
||||||
|
{
|
||||||
|
"name": "register more filters than allowed (default: 200)",
|
||||||
|
"register_err": "error creating filter: max limit reached",
|
||||||
|
"filters": make_filter_array(205),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "register some filters, remove 2 filters and check for updates",
|
||||||
|
"filters": filters,
|
||||||
|
"rm_filters_post_tx": 2,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for tc in test_cases:
|
||||||
|
print("\nCase: {}".format(tc["name"]))
|
||||||
|
|
||||||
|
# register the filters
|
||||||
|
fltrs = []
|
||||||
|
try:
|
||||||
|
for flt in tc["filters"]:
|
||||||
|
fltrs.append(w3.eth.filter(flt["params"]))
|
||||||
|
except Exception as err:
|
||||||
|
if "register_err" in tc:
|
||||||
|
# if exception was expected when registering filters
|
||||||
|
# the test is finished
|
||||||
|
assert tc["register_err"] in str(err)
|
||||||
|
# remove the registered filters
|
||||||
|
remove_filters(w3, fltrs, 300)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print(f"Unexpected {err=}, {type(err)=}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# without tx: filters should not return any entries
|
||||||
|
for flt in fltrs:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
|
||||||
|
# with tx
|
||||||
|
tx = contract.functions.setGreeting(new_greeting).build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
|
receipt = send_transaction(w3, tx)
|
||||||
|
assert receipt.status == 1
|
||||||
|
|
||||||
|
if "rm_filters_post_tx" in tc:
|
||||||
|
# remove the filters
|
||||||
|
remove_filters(w3, fltrs, tc["rm_filters_post_tx"])
|
||||||
|
|
||||||
|
for i, flt in enumerate(fltrs):
|
||||||
|
# if filters were removed, should get a 'filter not found' error
|
||||||
|
try:
|
||||||
|
new_entries = flt.get_new_entries() # GetFilterChanges
|
||||||
|
except Exception as err:
|
||||||
|
if "rm_filters_post_tx" in tc and i < tc["rm_filters_post_tx"]:
|
||||||
|
assert_no_filter_err(flt, err)
|
||||||
|
# filter was removed and error checked. Continue to next filter
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print(f"Unexpected {err=}, {type(err)=}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
assert len(new_entries) == tc["filters"][i]["exp_len"]
|
||||||
|
|
||||||
|
if tc["filters"][i]["exp_len"] == 1:
|
||||||
|
# check if the new_entries have valid information
|
||||||
|
log = new_entries[0]
|
||||||
|
assert log["address"] == contract.address
|
||||||
|
assert log["topics"] == [topic]
|
||||||
|
assert_log_block(w3, log)
|
||||||
|
assert_change_greet_log_data(log, new_greeting)
|
||||||
|
|
||||||
|
# on next call of GetFilterChanges, no entries should be found
|
||||||
|
# because there were no new logs that meet the filters params
|
||||||
|
for i, flt in enumerate(fltrs):
|
||||||
|
# if filters were removed, should get a 'filter not found' error
|
||||||
|
try:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
except Exception as err:
|
||||||
|
if "rm_filters_post_tx" in tc and i < tc["rm_filters_post_tx"]:
|
||||||
|
assert_no_filter_err(flt, err)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print(f"Unexpected {err=}, {type(err)=}")
|
||||||
|
raise
|
||||||
|
# remove the filters added on this test
|
||||||
|
# because the node is not reseted for each test
|
||||||
|
# otherwise may get a max-limit error for registering
|
||||||
|
# new filters
|
||||||
|
w3.eth.uninstall_filter(flt.filter_id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_register_filters_before_contract_deploy(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
|
new_greeting = "hello, world"
|
||||||
|
|
||||||
|
# calculate topic from event signature
|
||||||
|
topic = CHANGE_GREETING_TOPIC
|
||||||
|
# another topic not related to the contract deployed
|
||||||
|
another_topic = TRANSFER_TOPIC
|
||||||
|
|
||||||
|
filters = [
|
||||||
|
{
|
||||||
|
"params": {"topics": [topic.hex()]},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"topics": [
|
||||||
|
topic.hex(),
|
||||||
|
another_topic.hex(),
|
||||||
|
], # 'with all topics' condition
|
||||||
|
},
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"topics": [
|
||||||
|
[topic.hex(), another_topic.hex()]
|
||||||
|
], # 'with any topic' condition
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": {
|
||||||
|
"fromBlock": 1,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [[topic.hex(), another_topic.hex()]],
|
||||||
|
},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# register the filters
|
||||||
|
fltrs = []
|
||||||
|
for flt in filters:
|
||||||
|
fltrs.append(w3.eth.filter(flt["params"]))
|
||||||
|
|
||||||
|
# deploy contract
|
||||||
|
contract, _ = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
# test the contract was deployed successfully
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
|
||||||
|
# without tx: filters should not return any entries
|
||||||
|
for flt in fltrs:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
|
||||||
|
# perform tx to call contract that emits event
|
||||||
|
tx = contract.functions.setGreeting(new_greeting).build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
|
receipt = send_transaction(w3, tx)
|
||||||
|
assert receipt.status == 1
|
||||||
|
|
||||||
|
for i, flt in enumerate(fltrs):
|
||||||
|
new_entries = flt.get_new_entries() # GetFilterChanges
|
||||||
|
assert len(new_entries) == filters[i]["exp_len"]
|
||||||
|
|
||||||
|
if filters[i]["exp_len"] == 1:
|
||||||
|
# check if the new_entries have valid information
|
||||||
|
log = new_entries[0]
|
||||||
|
assert log["address"] == contract.address
|
||||||
|
assert log["topics"] == [topic]
|
||||||
|
assert_log_block(w3, log)
|
||||||
|
assert_change_greet_log_data(log, new_greeting)
|
||||||
|
|
||||||
|
# on next call of GetFilterChanges, no entries should be found
|
||||||
|
# because there were no new logs that meet the filters params
|
||||||
|
for flt in fltrs:
|
||||||
|
assert flt.get_new_entries() == [] # GetFilterChanges
|
||||||
|
w3.eth.uninstall_filter(flt.filter_id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_logs(cluster):
|
||||||
|
w3: Web3 = cluster.w3
|
||||||
|
|
||||||
|
# deploy greeter contract
|
||||||
|
contract, _ = deploy_contract(w3, CONTRACTS["Greeter"])
|
||||||
|
# test the contract was deployed successfully
|
||||||
|
assert contract.caller.greet() == "Hello"
|
||||||
|
|
||||||
|
# calculate topic from event signature
|
||||||
|
topic = CHANGE_GREETING_TOPIC
|
||||||
|
|
||||||
|
# another topic not related to the contract deployed
|
||||||
|
another_topic = TRANSFER_TOPIC
|
||||||
|
|
||||||
|
# without tx - logs should be empty
|
||||||
assert w3.eth.get_logs({"address": contract.address}) == []
|
assert w3.eth.get_logs({"address": contract.address}) == []
|
||||||
assert w3.eth.get_logs({"address": ADDRS["validator"]}) == []
|
assert w3.eth.get_logs({"address": ADDRS["validator"]}) == []
|
||||||
|
|
||||||
# with tx
|
# with tx
|
||||||
tx = contract.functions.setGreeting("world").build_transaction()
|
# update greeting
|
||||||
|
new_greeting = "hello, world"
|
||||||
|
tx = contract.functions.setGreeting(new_greeting).build_transaction(
|
||||||
|
{"from": ADDRS["validator"]}
|
||||||
|
)
|
||||||
receipt = send_transaction(w3, tx)
|
receipt = send_transaction(w3, tx)
|
||||||
assert receipt.status == 1
|
assert receipt.status == 1
|
||||||
|
|
||||||
assert len(w3.eth.get_logs({"address": contract.address})) == 1
|
tx_block_num = w3.eth.block_number
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
{
|
||||||
|
"name": "get logs by block range - tx block number is within the range",
|
||||||
|
"logs": w3.eth.get_logs({"fromBlock": 1, "toBlock": tx_block_num}),
|
||||||
|
"exp_log": True,
|
||||||
|
"exp_len": None, # there are other events within the block range specified
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by block range - tx block number outside the range",
|
||||||
|
"logs": w3.eth.get_logs({"fromBlock": 1, "toBlock": 2}),
|
||||||
|
"exp_log": False,
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by contract address",
|
||||||
|
"logs": w3.eth.get_logs({"address": contract.address}),
|
||||||
|
"exp_log": True,
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by topic",
|
||||||
|
"logs": w3.eth.get_logs({"topics": [topic.hex()]}),
|
||||||
|
"exp_log": True,
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by incorrect topic - should not have logs",
|
||||||
|
"logs": w3.eth.get_logs({"topics": [another_topic.hex()]}),
|
||||||
|
"exp_log": False,
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by multiple topics ('with all' condition)",
|
||||||
|
"logs": w3.eth.get_logs(
|
||||||
|
{
|
||||||
|
"topics": [
|
||||||
|
topic.hex(),
|
||||||
|
another_topic.hex(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"exp_log": False,
|
||||||
|
"exp_len": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by multiple topics ('match any' condition)",
|
||||||
|
"logs": w3.eth.get_logs({"topics": [[topic.hex(), another_topic.hex()]]}),
|
||||||
|
"exp_log": True,
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get logs by topic and block range",
|
||||||
|
"logs": w3.eth.get_logs(
|
||||||
|
{
|
||||||
|
"fromBlock": tx_block_num,
|
||||||
|
"toBlock": "latest",
|
||||||
|
"topics": [topic.hex()],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"exp_log": True,
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for tc in test_cases:
|
||||||
|
print("\nCase: {}".format(tc["name"]))
|
||||||
|
|
||||||
|
# logs for validator address should remain empty
|
||||||
assert len(w3.eth.get_logs({"address": ADDRS["validator"]})) == 0
|
assert len(w3.eth.get_logs({"address": ADDRS["validator"]})) == 0
|
||||||
|
|
||||||
|
logs = tc["logs"]
|
||||||
|
|
||||||
|
if tc["exp_len"] is not None:
|
||||||
|
assert len(logs) == tc["exp_len"]
|
||||||
|
|
||||||
|
if tc["exp_log"]:
|
||||||
|
found_log = False
|
||||||
|
|
||||||
|
for log in logs:
|
||||||
|
if log["address"] == contract.address:
|
||||||
|
# for the current test cases,
|
||||||
|
# this event was emitted only once
|
||||||
|
# so one log from this contract should exist
|
||||||
|
# we check the flag to know it is not repeated
|
||||||
|
assert found_log is False
|
||||||
|
|
||||||
|
found_log = True
|
||||||
|
|
||||||
|
assert log["topics"] == [topic]
|
||||||
|
assert_log_block(w3, log)
|
||||||
|
assert_change_greet_log_data(log, new_greeting)
|
||||||
|
|
||||||
|
assert found_log is True
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Helper functions to assert logs information
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
|
||||||
|
def assert_log_block(w3, log):
|
||||||
|
block_hash = log["blockHash"]
|
||||||
|
# check if the returned block hash is correct
|
||||||
|
# getBlockByHash
|
||||||
|
block = w3.eth.get_block(block_hash)
|
||||||
|
# block should exist
|
||||||
|
assert block.hash == block_hash
|
||||||
|
|
||||||
|
# check tx hash is correct
|
||||||
|
tx_data = w3.eth.get_transaction(log["transactionHash"])
|
||||||
|
assert tx_data["blockHash"] == block.hash
|
||||||
|
|
||||||
|
|
||||||
|
def assert_change_greet_log_data(log, new_greeting):
|
||||||
|
# check event log data ('from' and 'value' fields)
|
||||||
|
types = ["address", "string"]
|
||||||
|
names = ["from", "value"]
|
||||||
|
values = abi.decode_abi(types, log["data"])
|
||||||
|
log_data = dict(zip(names, values))
|
||||||
|
|
||||||
|
# the address stored in the data field may defer on lower/upper case characters
|
||||||
|
# then, set all as lowercase for assertion
|
||||||
|
assert log_data["from"] == ADDRS["validator"].lower()
|
||||||
|
assert log_data["value"] == new_greeting
|
||||||
|
|
||||||
|
|
||||||
|
def assert_no_filter_err(flt, err):
|
||||||
|
msg_without_id = "filter not found" in str(err)
|
||||||
|
msg_with_id = f"filter {flt.filter_id} not found" in str(err)
|
||||||
|
assert msg_without_id or msg_with_id is True
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Helper functions to add/remove filters
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
|
||||||
|
def make_filter_array(array_len):
|
||||||
|
filters = []
|
||||||
|
for _ in range(array_len):
|
||||||
|
filters.append(
|
||||||
|
{
|
||||||
|
"params": {"fromBlock": 1, "toBlock": "latest"},
|
||||||
|
"exp_len": 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return filters
|
||||||
|
|
||||||
|
|
||||||
|
# removes the number of filters defined in 'count' argument, starting from index 0
|
||||||
|
def remove_filters(w3, filters, count):
|
||||||
|
# if number of filters to remove exceeds the amount of filters passed
|
||||||
|
# update the 'count' to the length of the filters array
|
||||||
|
if count > len(filters):
|
||||||
|
count = len(filters)
|
||||||
|
|
||||||
|
for i in range(count):
|
||||||
|
assert w3.eth.uninstall_filter(filters[i].filter_id)
|
||||||
|
|
||||||
|
|
||||||
|
# adds a padding of '0's to a hex address based on the total byte length desired
|
||||||
|
def pad_left(address, byte_len=32):
|
||||||
|
a = address.split("0x")
|
||||||
|
b = a[1].zfill(byte_len * 2)
|
||||||
|
return "0x" + b
|
||||||
|
@ -30,13 +30,14 @@ TEST_CONTRACTS = {
|
|||||||
"Greeter": "Greeter.sol",
|
"Greeter": "Greeter.sol",
|
||||||
"BurnGas": "BurnGas.sol",
|
"BurnGas": "BurnGas.sol",
|
||||||
"TestChainID": "ChainID.sol",
|
"TestChainID": "ChainID.sol",
|
||||||
|
"Mars": "Mars.sol",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def contract_path(name, filename):
|
def contract_path(name, filename):
|
||||||
return (
|
return (
|
||||||
Path(__file__).parent
|
Path(__file__).parent
|
||||||
/ "contracts/artifacts/contracts/"
|
/ "hardhat/artifacts/contracts/"
|
||||||
/ filename
|
/ filename
|
||||||
/ (name + ".json")
|
/ (name + ".json")
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user
Variable defined multiple times
This assignment to 'test_get_logs_by_topic' is unnecessary as it is redefined before this value is used.
Show more details