solver-multirpc 3.1.4__tar.gz → 3.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solver-multirpc
3
- Version: 3.1.4
3
+ Version: 3.1.6
4
4
  Summary: A robust Python library for interacting with Ethereum smart contracts via multiple RPC endpoints, ensuring reliability, availability, and load distribution with automatic retries on failure.
5
5
  License: MIT
6
6
  Author: rorschach
@@ -51,8 +51,8 @@ Below is an example of how to use the AsyncMultiRpc class for asynchronous opera
51
51
  ```python
52
52
  import asyncio
53
53
  import json
54
- from src.multirpc.utils import NestedDict
55
- from multirpc import AsyncMultiRpc
54
+ from multirpc.utils import NestedDict
55
+ from multirpc.async_multi_rpc_interface import AsyncMultiRpc
56
56
 
57
57
 
58
58
  async def main():
@@ -32,8 +32,8 @@ Below is an example of how to use the AsyncMultiRpc class for asynchronous opera
32
32
  ```python
33
33
  import asyncio
34
34
  import json
35
- from src.multirpc.utils import NestedDict
36
- from multirpc import AsyncMultiRpc
35
+ from multirpc.utils import NestedDict
36
+ from multirpc.async_multi_rpc_interface import AsyncMultiRpc
37
37
 
38
38
 
39
39
  async def main():
@@ -1,4 +1,4 @@
1
- from src.multirpc.tx_trace import TxTrace
1
+ from multirpc.tx_trace import TxTrace
2
2
 
3
3
  BaseException_ = Exception
4
4
 
@@ -29,12 +29,16 @@ class TransactionFailedStatus(Web3InterfaceException):
29
29
  self.trace: TxTrace = trace
30
30
 
31
31
  def __str__(self):
32
- return (f'{self.__class__.__name__}({self.hex_tx_hash} func={self.func_name}, '
33
- f'{self.func_name=}, {self.func_kwargs=}, {self.trace=})')
32
+ return self.__repr__()
34
33
 
35
34
  def __repr__(self):
36
- return (f'{self.__class__.__name__}({self.hex_tx_hash} func={self.func_name}, '
37
- f'{self.func_name=}, {self.func_kwargs=}, {self.trace=})')
35
+ ret = (f'{self.__class__.__name__}({self.hex_tx_hash}, {self.func_name=}, '
36
+ f'{self.func_args=}, {self.func_kwargs=})')
37
+ if self.trace and self.trace.ok():
38
+ main_error = self.trace.result().first_usable_error()
39
+ ret += f' {main_error=}'
40
+
41
+ return ret
38
42
 
39
43
 
40
44
  class FailedToGetGasPrice(Web3InterfaceException):
@@ -1,6 +1,6 @@
1
1
  import requests
2
2
 
3
- from src.multirpc.constants import MultiRPCLogger
3
+ from multirpc.constants import MultiRPCLogger
4
4
 
5
5
 
6
6
  class TxTrace:
@@ -1,12 +1,12 @@
1
1
  [tool.poetry]
2
2
  name = "solver-multirpc"
3
- version = "3.1.4"
3
+ version = "3.1.6"
4
4
  description = "A robust Python library for interacting with Ethereum smart contracts via multiple RPC endpoints, ensuring reliability, availability, and load distribution with automatic retries on failure."
5
5
  authors = ["rorschach <rorschach45001@gmail.com>"]
6
6
  license = "MIT"
7
7
  readme = "README.md"
8
8
  packages = [
9
- { include = "src" }
9
+ { include = "multirpc" }
10
10
  ]
11
11
 
12
12
  [tool.poetry.dependencies]
File without changes
File without changes
@@ -1,34 +0,0 @@
1
- [
2
- {
3
- "inputs": [
4
- {
5
- "internalType": "uint256",
6
- "name": "value",
7
- "type": "uint256"
8
- }
9
- ],
10
- "name": "set",
11
- "outputs": [],
12
- "stateMutability": "nonpayable",
13
- "type": "function"
14
- },
15
- {
16
- "inputs": [
17
- {
18
- "internalType": "address",
19
- "name": "",
20
- "type": "address"
21
- }
22
- ],
23
- "name": "map",
24
- "outputs": [
25
- {
26
- "internalType": "uint256",
27
- "name": "",
28
- "type": "uint256"
29
- }
30
- ],
31
- "stateMutability": "view",
32
- "type": "function"
33
- }
34
- ]
@@ -1,78 +0,0 @@
1
- import json
2
-
3
- from src.multirpc.utils import ChainConfigTest, NestedDict
4
-
5
- # Arbitrum Configuration
6
- ArbConfig = ChainConfigTest(
7
- 'Arbitrum',
8
- '0xCFE3c06Fe982A7D16ce3826C64c5f0730054Dc95',
9
- NestedDict({
10
- "view": {
11
- 1: ['https://1rpc.io/arb', 'https://rpc.ankr.com/arbitrum', 'https://arbitrum.drpc.org'],
12
- },
13
- "transaction": {
14
- 1: ['https://1rpc.io/arb', 'https://rpc.ankr.com/arbitrum', 'https://arbitrum.drpc.org'],
15
- }
16
- }),
17
- '0xbc0f34536fdf5d2593081b112d49d714993d879032e0e9c6998afc3110b7f0ed'
18
- )
19
-
20
- # Polygon Configuration
21
- PolyConfig = ChainConfigTest(
22
- 'Polygon',
23
- '0xCa7DFDc4dB0F27484Cf5EEa1CdF380301Ef07Ce2',
24
- NestedDict({
25
- "view": {
26
- 1: ['https://1rpc.io/matic', 'https://polygon-rpc.com'],
27
- },
28
- "transaction": {
29
- 1: ['https://1rpc.io/matic', 'https://polygon-rpc.com'],
30
- }
31
- }),
32
- '0x4b8756bd1d32f62b2b9e3b46b80917bd3de4fd95695bad33e483293284f28678',
33
- is_proof_authority=True
34
- )
35
-
36
- # Base Configuration
37
- BaseConfig = ChainConfigTest(
38
- 'Base',
39
- '0x1d58e7F58d085c87E34b18DAe5A6D08d187cbcbe',
40
- NestedDict({
41
- "view": {
42
- 1: ['https://base-rpc.publicnode.com', 'https://base.drpc.org'],
43
- },
44
- "transaction": {
45
- 1: ['https://base-rpc.publicnode.com', 'https://base.drpc.org'],
46
- }
47
- }),
48
- '0xbd342d36d503af057cd79fd4f252b4629d6013d0748a2742dc99c9fcbe522072',
49
- is_proof_authority=True
50
- )
51
-
52
- # Mantle Configuration
53
- MantleConfig = ChainConfigTest(
54
- 'Mantle',
55
- '0x535D41D93cDc0818Ad8Eeb452B74e502A5742874',
56
- NestedDict({
57
- "view": {
58
- 1: ['https://1rpc.io/mantle', 'https://mantle.drpc.org'],
59
- },
60
- "transaction": {
61
- 1: ['https://1rpc.io/mantle', 'https://mantle.drpc.org'],
62
- }
63
- }),
64
- '0x9f33a56be9983753abebbe8fb048601a141097289d96b9844afb36e68f72ef82',
65
- is_proof_authority=False,
66
- )
67
-
68
- RPCsSupportingTxTrace = [
69
- 'https://arbitrum.drpc.org', # Arbitrum
70
- 'https://polygon-rpc.com', # Polygon
71
- 'https://base.drpc.org', # Base
72
- 'https://mantle.drpc.org' # Mantle
73
- ]
74
-
75
- with open("tests/abi.json", "r") as f:
76
- abi = json.load(f)
77
-
78
- PreviousBlock = 3
@@ -1,16 +0,0 @@
1
- // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity ^0.8.9;
3
-
4
- contract Mapping {
5
- mapping(address => uint256) public map;
6
-
7
- function set(uint256 value) public {
8
- // Revert if the input is exactly one byte of 0x00
9
- require(
10
- value >= 10,
11
- "Error: 10 < value is not allowed."
12
- );
13
-
14
- map[msg.sender] = value;
15
- }
16
- }
@@ -1,138 +0,0 @@
1
- import asyncio
2
- import logging
3
- import random
4
-
5
- from eth_account import Account
6
- from web3.exceptions import MismatchedABI
7
-
8
- from src.multirpc.async_multi_rpc_interface import AsyncMultiRpc
9
- from src.multirpc.constants import GasEstimationMethod, ViewPolicy
10
- from src.multirpc.sync_multi_rpc_interface import MultiRpc
11
- from src.multirpc.utils import ChainConfigTest
12
- from src.tests.constants import ArbConfig, BaseConfig, PolyConfig, RPCsSupportingTxTrace, abi
13
- from src.tests.test_settings import LogLevel, PrivateKey1, PrivateKey2
14
-
15
- PreviousBlock = 3
16
-
17
-
18
- async def async_test_map(mr: AsyncMultiRpc, addr: str = None, pk: str = None):
19
- random_int = random.randint(10, 100)
20
- print(f"Random int: {random_int}")
21
- # await mr.functions.set(random_int).call(address=addr, private_key=pk,
22
- # gas_estimation_method=GasEstimationMethod.GAS_API_PROVIDER)
23
- # await mr.functions.set(random_int).call(address=addr, private_key=pk,
24
- # gas_estimation_method=GasEstimationMethod.FIXED)
25
-
26
- # for failure purpose
27
- try:
28
- await mr.functions.set(random_int, random_int).call(address=addr, private_key=pk,
29
- gas_estimation_method=GasEstimationMethod.RPC)
30
- except MismatchedABI:
31
- pass
32
-
33
- type(random_int)
34
-
35
- try:
36
- await mr.functions.set(random.randint(1, 9)
37
- ).call(address=addr, private_key=pk,
38
- gas_estimation_method=GasEstimationMethod.RPC,
39
- enable_estimate_gas_limit=False
40
- )
41
- except Exception as e:
42
- print(e)
43
-
44
- print(f'encoded function: {mr.functions.set(random_int).get_encoded_data()}')
45
- tx_receipt = await mr.functions.set(random_int).call(address=addr, private_key=pk,
46
- gas_estimation_method=GasEstimationMethod.RPC)
47
-
48
- print(f"{tx_receipt=}")
49
- result = await mr.functions.map(addr).call()
50
- print(f"map(addr: {addr}): {result}")
51
- assert random_int == result, "test was not successful"
52
-
53
-
54
- async def async_main(chain_config: ChainConfigTest):
55
- multi_rpc = AsyncMultiRpc(chain_config.rpc, chain_config.contract_address,
56
- rpcs_supporting_tx_trace=RPCsSupportingTxTrace,
57
- view_policy=ViewPolicy.MostUpdated,
58
- contract_abi=abi, gas_estimation=None, log_level=LogLevel,
59
- is_proof_authority=config_.is_proof_authority,
60
- multicall_custom_address=chain_config.multicall_address, enable_estimate_gas_limit=True)
61
- multi_rpc.set_account(address1, private_key=PrivateKey1)
62
-
63
- p_block = await multi_rpc.get_block_number() - PreviousBlock
64
- print(f"tx_receipt: {await multi_rpc.get_tx_receipt(chain_config.tx_hash)}")
65
- print(f"block: {await multi_rpc.get_block(p_block - 1000)}")
66
- print(f"Nonce: {await multi_rpc.get_nonce(address1)}")
67
- print(f"map({address1}): {await multi_rpc.functions.map(address1).call()}")
68
-
69
- results = await multi_rpc.functions.map([(address1,), (address2,)] * 100).multicall()
70
- print(f"map({address1, address2}): {[res for res in results]}")
71
- print(f"map({address1}) in {p_block=}: "
72
- f"{await multi_rpc.functions.map(address1).call(block_identifier=p_block)}")
73
-
74
- await async_test_map(multi_rpc, address1)
75
- # await async_test_map(multi_rpc, address2, PrivateKey2)
76
-
77
-
78
- def sync_test_map(mr: MultiRpc, addr: str = None, pk: str = None):
79
- random_int = random.randint(10, 100)
80
- print(f"Random int: {random_int}")
81
- print(f'encoded function: {mr.functions.set(random_int).get_encoded_data()}')
82
- mr.functions.set(random_int).call(address=addr, private_key=pk)
83
-
84
- result = mr.functions.map(addr).call()
85
- print(f"map(addr: {addr}): {result}")
86
- assert random_int == result, "test was not successful"
87
-
88
-
89
- def sync_main(chain_config: ChainConfigTest):
90
- multi_rpc = MultiRpc(chain_config.rpc, chain_config.contract_address, contract_abi=abi,
91
- rpcs_supporting_tx_trace=RPCsSupportingTxTrace,
92
- gas_estimation=None,
93
- enable_estimate_gas_limit=True, log_level=LogLevel,
94
- is_proof_authority=config_.is_proof_authority,
95
- multicall_custom_address=chain_config.multicall_address)
96
- multi_rpc.set_account(address1, private_key=PrivateKey1)
97
-
98
- p_block = multi_rpc.get_block_number() - PreviousBlock
99
- print(f"tx_receipt: {multi_rpc.get_tx_receipt(chain_config.tx_hash)}")
100
- print(f"block: {multi_rpc.get_block(p_block - 1000)}")
101
- print(f"Nonce: {multi_rpc.get_nonce(address1)}")
102
- print(f"map({address1}): {multi_rpc.functions.map(address1).call()}")
103
-
104
- results = multi_rpc.functions.map([(address1,), (address2,)]).multicall()
105
- print(f"map({address1, address2}): {[res for res in results]}")
106
- print(f"map({address1}) in {p_block=}: "
107
- f"{multi_rpc.functions.map(address1).call(block_identifier=p_block)}")
108
-
109
- sync_test_map(multi_rpc, address1)
110
- sync_test_map(multi_rpc, address2, PrivateKey2)
111
-
112
-
113
- async def test(chain_config: ChainConfigTest):
114
- # try:
115
- # sync_main(chain_config)
116
- # print("###sync test was successful###")
117
- # except Exception as e:
118
- # logging.error(e)
119
-
120
- try:
121
- await async_main(chain_config)
122
- print('###async test was successful###')
123
- except Exception as e:
124
- logging.error(e)
125
-
126
-
127
- if __name__ == '__main__':
128
- address1 = Account.from_key(PrivateKey1).address
129
- address2 = Account.from_key(PrivateKey2).address
130
- for config_ in [
131
- ArbConfig,
132
- PolyConfig,
133
- BaseConfig,
134
- # MantleConfig
135
- ]:
136
- print(f"=============================== Start Testing on {config_.name} ===============================")
137
- asyncio.run(test(config_))
138
- print(f"=============================== Test on {config_.name} Completed ===============================\n\n")
@@ -1,7 +0,0 @@
1
- import logging
2
-
3
- # private key that have gas for in fantom network
4
- PrivateKey1 = ""
5
- PrivateKey2 = ""
6
-
7
- LogLevel = logging.INFO