chore_: implement eth service for use in integration tests (#5903)
This commit is contained in:
parent
c1dd9397f7
commit
e8bd4d5685
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/status-im/status-go/services/communitytokens"
|
"github.com/status-im/status-go/services/communitytokens"
|
||||||
"github.com/status-im/status-go/services/connector"
|
"github.com/status-im/status-go/services/connector"
|
||||||
"github.com/status-im/status-go/services/ens"
|
"github.com/status-im/status-go/services/ens"
|
||||||
|
"github.com/status-im/status-go/services/eth"
|
||||||
"github.com/status-im/status-go/services/gif"
|
"github.com/status-im/status-go/services/gif"
|
||||||
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
||||||
"github.com/status-im/status-go/services/mailservers"
|
"github.com/status-im/status-go/services/mailservers"
|
||||||
|
@ -132,6 +133,7 @@ type StatusNode struct {
|
||||||
pendingTracker *transactions.PendingTxTracker
|
pendingTracker *transactions.PendingTxTracker
|
||||||
connectorSrvc *connector.Service
|
connectorSrvc *connector.Service
|
||||||
appGeneralSrvc *appgeneral.Service
|
appGeneralSrvc *appgeneral.Service
|
||||||
|
ethSrvc *eth.Service
|
||||||
|
|
||||||
accountsFeed event.Feed
|
accountsFeed event.Feed
|
||||||
walletFeed event.Feed
|
walletFeed event.Feed
|
||||||
|
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"github.com/status-im/status-go/services/communitytokens"
|
"github.com/status-im/status-go/services/communitytokens"
|
||||||
"github.com/status-im/status-go/services/connector"
|
"github.com/status-im/status-go/services/connector"
|
||||||
"github.com/status-im/status-go/services/ens"
|
"github.com/status-im/status-go/services/ens"
|
||||||
|
"github.com/status-im/status-go/services/eth"
|
||||||
"github.com/status-im/status-go/services/ext"
|
"github.com/status-im/status-go/services/ext"
|
||||||
"github.com/status-im/status-go/services/gif"
|
"github.com/status-im/status-go/services/gif"
|
||||||
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
||||||
|
@ -174,6 +175,8 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
||||||
}
|
}
|
||||||
services = append(services, lns)
|
services = append(services, lns)
|
||||||
|
|
||||||
|
services = append(services, b.ethService())
|
||||||
|
|
||||||
b.peerSrvc.SetDiscoverer(b)
|
b.peerSrvc.SetDiscoverer(b)
|
||||||
|
|
||||||
for i := range services {
|
for i := range services {
|
||||||
|
@ -617,6 +620,13 @@ func (b *StatusNode) peerService() *peer.Service {
|
||||||
return b.peerSrvc
|
return b.peerSrvc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) ethService() *eth.Service {
|
||||||
|
if b.ethSrvc == nil {
|
||||||
|
b.ethSrvc = eth.NewService(b.rpcClient)
|
||||||
|
}
|
||||||
|
return b.ethSrvc
|
||||||
|
}
|
||||||
|
|
||||||
func registerWakuMailServer(wakuService *waku.Waku, config *params.WakuConfig) (err error) {
|
func registerWakuMailServer(wakuService *waku.Waku, config *params.WakuConfig) (err error) {
|
||||||
var mailServer mailserver.WakuMailServer
|
var mailServer mailserver.WakuMailServer
|
||||||
wakuService.RegisterMailServer(&mailServer)
|
wakuService.RegisterMailServer(&mailServer)
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
//go:build enable_private_api
|
||||||
|
|
||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
geth_rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func privateAPIs(client *rpc.Client) (apis []geth_rpc.API) {
|
||||||
|
return []geth_rpc.API{
|
||||||
|
{
|
||||||
|
Namespace: "ethclient",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewPrivateAPI(client),
|
||||||
|
Public: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateAPI struct {
|
||||||
|
client *rpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrivateAPI(client *rpc.Client) *PrivateAPI {
|
||||||
|
return &PrivateAPI{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
type blockResponse struct {
|
||||||
|
Header *types.Header `json:"header"`
|
||||||
|
Transactions types.Transactions `json:"transactions"`
|
||||||
|
Withdrawals types.Withdrawals `json:"withdrawals"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBlockResponse(b *types.Block) *blockResponse {
|
||||||
|
return &blockResponse{
|
||||||
|
Header: b.Header(),
|
||||||
|
Transactions: b.Transactions(),
|
||||||
|
Withdrawals: b.Withdrawals(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) BlockByHash(ctx context.Context, chainId uint64, hash common.Hash) (*blockResponse, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := client.BlockByHash(ctx, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBlockResponse(block), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) BlockByNumber(ctx context.Context, chainId uint64, number *hexutil.Big) (*blockResponse, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, err := client.BlockByNumber(ctx, (*big.Int)(number))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBlockResponse(block), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) HeaderByHash(ctx context.Context, chainId uint64, hash common.Hash) (*types.Header, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.HeaderByHash(ctx, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) HeaderByNumber(ctx context.Context, chainId uint64, number *hexutil.Big) (*types.Header, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.HeaderByNumber(ctx, (*big.Int)(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
type transactionByHashResponse struct {
|
||||||
|
Tx *types.Transaction `json:"tx"`
|
||||||
|
IsPending bool `json:"isPending"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) TransactionByHash(ctx context.Context, chainId uint64, txHash common.Hash) (*transactionByHashResponse, error) {
|
||||||
|
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, isPending, err := client.TransactionByHash(ctx, txHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := &transactionByHashResponse{
|
||||||
|
Tx: tx,
|
||||||
|
IsPending: isPending,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) TransactionReceipt(ctx context.Context, chainId uint64, txHash common.Hash) (*types.Receipt, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.TransactionReceipt(ctx, txHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) SuggestGasPrice(ctx context.Context, chainId uint64) (*hexutil.Big, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := client.SuggestGasPrice(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*hexutil.Big)(ret), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pa *PrivateAPI) BlockNumber(ctx context.Context, chainId uint64) (uint64, error) {
|
||||||
|
client, err := pa.client.EthClient(chainId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.BlockNumber(ctx)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !enable_private_api
|
||||||
|
|
||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
geth_rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/status-im/status-go/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func privateAPIs(*rpc.Client) (apis []geth_rpc.API) {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
geth_rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
|
rpc_client "github.com/status-im/status-go/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
rpcClient *rpc_client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(
|
||||||
|
rpcClient *rpc_client.Client,
|
||||||
|
) *Service {
|
||||||
|
return &Service{
|
||||||
|
rpcClient: rpcClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) APIs() []geth_rpc.API {
|
||||||
|
return privateAPIs(s.rpcClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Protocols() []p2p.Protocol {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
"HTTPHost": "0.0.0.0",
|
"HTTPHost": "0.0.0.0",
|
||||||
"HTTPPort": 3333,
|
"HTTPPort": 3333,
|
||||||
"HTTPVirtualHosts": ["*", "status-go"],
|
"HTTPVirtualHosts": ["*", "status-go"],
|
||||||
"APIModules": "eth,admin,wallet,accounts,waku,wakuext",
|
"APIModules": "eth,admin,wallet,accounts,waku,wakuext,ethclient",
|
||||||
"WalletConfig": {
|
"WalletConfig": {
|
||||||
"Enabled": true
|
"Enabled": true
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ services:
|
||||||
context: ../
|
context: ../
|
||||||
dockerfile: _assets/build/Dockerfile
|
dockerfile: _assets/build/Dockerfile
|
||||||
args:
|
args:
|
||||||
build_tags: gowaku_no_rln
|
build_tags: gowaku_no_rln,enable_private_api
|
||||||
build_target: statusd
|
build_target: statusd
|
||||||
build_flags: -cover
|
build_flags: -cover
|
||||||
entrypoint: [
|
entrypoint: [
|
||||||
|
@ -37,7 +37,7 @@ services:
|
||||||
context: ../
|
context: ../
|
||||||
dockerfile: _assets/build/Dockerfile
|
dockerfile: _assets/build/Dockerfile
|
||||||
args:
|
args:
|
||||||
build_tags: gowaku_no_rln
|
build_tags: gowaku_no_rln,enable_private_api
|
||||||
build_target: statusd
|
build_target: statusd
|
||||||
build_flags: -cover
|
build_flags: -cover
|
||||||
entrypoint: [
|
entrypoint: [
|
||||||
|
@ -72,7 +72,7 @@ services:
|
||||||
dockerfile: Dockerfile.tests-rpc
|
dockerfile: Dockerfile.tests-rpc
|
||||||
entrypoint: [
|
entrypoint: [
|
||||||
"pytest",
|
"pytest",
|
||||||
"-m", "wallet",
|
"-m", "wallet or ethclient",
|
||||||
"--rpc_url=http://status-go:3333",
|
"--rpc_url=http://status-go:3333",
|
||||||
"--rpc_url_2=http://status-go-no-funds:3333",
|
"--rpc_url_2=http://status-go-no-funds:3333",
|
||||||
"--anvil_url=http://anvil:8545",
|
"--anvil_url=http://anvil:8545",
|
||||||
|
|
|
@ -10,3 +10,4 @@ markers =
|
||||||
tx
|
tx
|
||||||
wakuext
|
wakuext
|
||||||
accounts
|
accounts
|
||||||
|
ethclient
|
||||||
|
|
|
@ -6,12 +6,14 @@ import jsonschema
|
||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
from conftest import option, user_1, user_2
|
from conftest import option, user_1, user_2
|
||||||
|
import pytest
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
class RpcTestCase:
|
class RpcTestCase:
|
||||||
|
network_id = 31337
|
||||||
|
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
self.network_id = 31337
|
pass
|
||||||
|
|
||||||
def _try_except_JSONDecodeError_KeyError(self, response, key: str):
|
def _try_except_JSONDecodeError_KeyError(self, response, key: str):
|
||||||
try:
|
try:
|
||||||
|
@ -56,13 +58,19 @@ class RpcTestCase:
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def rpc_valid_request(self, method, params=[], _id=None, client=None, url=None):
|
||||||
|
response = self.rpc_request(method, params, _id, client, url)
|
||||||
|
self.verify_is_valid_json_rpc_response(response, _id)
|
||||||
|
return response
|
||||||
|
|
||||||
def verify_json_schema(self, response, method):
|
def verify_json_schema(self, response, method):
|
||||||
with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
|
with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
|
||||||
jsonschema.validate(instance=response.json(),
|
jsonschema.validate(instance=response.json(),
|
||||||
schema=json.load(schema))
|
schema=json.load(schema))
|
||||||
|
|
||||||
|
class WalletTestCase(RpcTestCase):
|
||||||
class TransactionTestCase(RpcTestCase):
|
def setup_method(self):
|
||||||
|
super().setup_method()
|
||||||
|
|
||||||
def wallet_create_multi_transaction(self, **kwargs):
|
def wallet_create_multi_transaction(self, **kwargs):
|
||||||
method = "wallet_createMultiTransaction"
|
method = "wallet_createMultiTransaction"
|
||||||
|
@ -88,7 +96,7 @@ class TransactionTestCase(RpcTestCase):
|
||||||
"fromAddress": user_1.address,
|
"fromAddress": user_1.address,
|
||||||
"fromAmount": "0x5af3107a4000",
|
"fromAmount": "0x5af3107a4000",
|
||||||
"fromAsset": "ETH",
|
"fromAsset": "ETH",
|
||||||
"multiTxType": "MultiTransactionSend",
|
"type": 0, # MultiTransactionSend
|
||||||
"toAddress": user_2.address,
|
"toAddress": user_2.address,
|
||||||
"toAsset": "ETH",
|
"toAsset": "ETH",
|
||||||
},
|
},
|
||||||
|
@ -101,19 +109,66 @@ class TransactionTestCase(RpcTestCase):
|
||||||
],
|
],
|
||||||
f"{option.password}",
|
f"{option.password}",
|
||||||
]
|
]
|
||||||
response = self.rpc_request(method, params, 13)
|
return self.rpc_request(method, params)
|
||||||
return response
|
|
||||||
|
|
||||||
def setup_method(self):
|
def send_valid_multi_transaction(self, **kwargs):
|
||||||
super().setup_method()
|
response = self.wallet_create_multi_transaction(**kwargs)
|
||||||
|
|
||||||
response = self.wallet_create_multi_transaction()
|
tx_hash = None
|
||||||
|
self.verify_is_valid_json_rpc_response(response)
|
||||||
try:
|
try:
|
||||||
self.tx_hash = response.json(
|
tx_hash = response.json(
|
||||||
)["result"]["hashes"][str(self.network_id)][0]
|
)["result"]["hashes"][str(self.network_id)][0]
|
||||||
except (KeyError, json.JSONDecodeError):
|
except (KeyError, json.JSONDecodeError):
|
||||||
raise Exception(response.content)
|
raise Exception(response.content)
|
||||||
|
return tx_hash
|
||||||
|
|
||||||
|
class TransactionTestCase(WalletTestCase):
|
||||||
|
def setup_method(self):
|
||||||
|
super().setup_method()
|
||||||
|
|
||||||
|
self.tx_hash = self.send_valid_multi_transaction()
|
||||||
|
|
||||||
|
class EthApiTestCase(WalletTestCase):
|
||||||
|
@pytest.fixture(autouse=True, scope='class')
|
||||||
|
def tx_data(self):
|
||||||
|
tx_hash = self.send_valid_multi_transaction()
|
||||||
|
self.wait_until_tx_not_pending(tx_hash)
|
||||||
|
|
||||||
|
receipt = self.get_transaction_receipt(tx_hash)
|
||||||
|
try:
|
||||||
|
block_number = receipt.json()["result"]["blockNumber"]
|
||||||
|
block_hash = receipt.json()["result"]["blockHash"]
|
||||||
|
except (KeyError, json.JSONDecodeError):
|
||||||
|
raise Exception(receipt.content)
|
||||||
|
|
||||||
|
TxData = namedtuple("TxData", ["tx_hash", "block_number", "block_hash"])
|
||||||
|
return TxData(tx_hash, block_number, block_hash)
|
||||||
|
|
||||||
|
def get_block_header(self, block_number):
|
||||||
|
method = "ethclient_headerByNumber"
|
||||||
|
params = [self.network_id, block_number]
|
||||||
|
return self.rpc_valid_request(method, params)
|
||||||
|
|
||||||
|
def get_transaction_receipt(self, tx_hash):
|
||||||
|
method = "ethclient_transactionReceipt"
|
||||||
|
params = [self.network_id, tx_hash]
|
||||||
|
return self.rpc_valid_request(method, params)
|
||||||
|
|
||||||
|
def wait_until_tx_not_pending(self, tx_hash, timeout=10):
|
||||||
|
method = "ethclient_transactionByHash"
|
||||||
|
params = [self.network_id, tx_hash]
|
||||||
|
response = self.rpc_valid_request(method, params)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
while response.json()["result"]["isPending"] == True:
|
||||||
|
time_passed = time.time() - start_time
|
||||||
|
if time_passed >= timeout:
|
||||||
|
raise TimeoutError(
|
||||||
|
f"Tx {tx_hash} is still pending after {timeout} seconds")
|
||||||
|
time.sleep(0.5)
|
||||||
|
response = self.rpc_valid_request(method, params)
|
||||||
|
return response.json()["result"]["tx"]
|
||||||
|
|
||||||
class SignalTestCase(RpcTestCase):
|
class SignalTestCase(RpcTestCase):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import pytest
|
||||||
|
from conftest import option
|
||||||
|
from test_cases import EthApiTestCase
|
||||||
|
|
||||||
|
def validateHeader(header, block_number, block_hash):
|
||||||
|
assert header["number"] == block_number
|
||||||
|
assert header["hash"] == block_hash
|
||||||
|
|
||||||
|
def validateBlock(block, block_number, block_hash, expected_tx_hash):
|
||||||
|
validateHeader(block["header"], block_number, block_hash)
|
||||||
|
tx_hashes = [tx["hash"] for tx in block["transactions"]]
|
||||||
|
assert expected_tx_hash in tx_hashes
|
||||||
|
|
||||||
|
def validateTransaction(tx, tx_hash):
|
||||||
|
assert tx["tx"]["hash"] == tx_hash
|
||||||
|
|
||||||
|
def validateReceipt(receipt, tx_hash, block_number, block_hash):
|
||||||
|
assert receipt["transactionHash"] == tx_hash
|
||||||
|
assert receipt["blockNumber"] == block_number
|
||||||
|
assert receipt["blockHash"] == block_hash
|
||||||
|
|
||||||
|
@pytest.mark.rpc
|
||||||
|
@pytest.mark.ethclient
|
||||||
|
class TestRpc(EthApiTestCase):
|
||||||
|
def test_block_number(self):
|
||||||
|
self.rpc_valid_request("ethclient_blockNumber", [self.network_id])
|
||||||
|
|
||||||
|
def test_suggest_gas_price(self):
|
||||||
|
self.rpc_valid_request("ethclient_suggestGasPrice", [self.network_id])
|
||||||
|
|
||||||
|
def test_header_by_number(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_headerByNumber", [self.network_id, tx_data.block_number])
|
||||||
|
validateHeader(response.json()["result"], tx_data.block_number, tx_data.block_hash)
|
||||||
|
|
||||||
|
def test_block_by_number(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_blockByNumber", [self.network_id, tx_data.block_number])
|
||||||
|
validateBlock(response.json()["result"], tx_data.block_number, tx_data.block_hash, tx_data.tx_hash)
|
||||||
|
|
||||||
|
def test_header_by_hash(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_headerByHash", [self.network_id, tx_data.block_hash])
|
||||||
|
validateHeader(response.json()["result"], tx_data.block_number, tx_data.block_hash)
|
||||||
|
|
||||||
|
def test_block_by_hash(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_blockByHash", [self.network_id, tx_data.block_hash])
|
||||||
|
validateBlock(response.json()["result"], tx_data.block_number, tx_data.block_hash, tx_data.tx_hash)
|
||||||
|
|
||||||
|
def test_transaction_by_hash(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_transactionByHash", [self.network_id, tx_data.tx_hash])
|
||||||
|
validateTransaction(response.json()["result"], tx_data.tx_hash)
|
||||||
|
|
||||||
|
def test_transaction_receipt(self, tx_data):
|
||||||
|
response = self.rpc_valid_request("ethclient_transactionReceipt", [self.network_id, tx_data.tx_hash])
|
||||||
|
validateReceipt(response.json()["result"], tx_data.tx_hash, tx_data.block_number, tx_data.block_hash)
|
Loading…
Reference in New Issue