Skip to content

Commit f237fa7

Browse files
committed
put in retry for SEQUENCE errors
1 parent 713a5ff commit f237fa7

File tree

2 files changed

+44
-23
lines changed

2 files changed

+44
-23
lines changed

convex_api/convex_api.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import logging
1010
from urllib.parse import urljoin
1111
import requests
12+
import secrets
13+
import time
1214

1315

1416
from eth_utils import remove_0x_prefix
@@ -34,12 +36,16 @@ def __init__(self, url, language=LANGUAGE_LISP):
3436
raise ValueError(f'Invalid language: {language}')
3537
self._language = language
3638

37-
def send(self, transaction, account, language=None):
39+
def send(self, transaction, account, language=None, sequence_retry_count=20):
3840
"""
3941
Send transaction code to the block chain node.
4042
4143
:param str transaction: The transaction as a string to send
4244
:param Account account: The account that needs to sign the message to send
45+
:param str language: Language to use for this transaction. Defaults to LANGUAGE_LISP.
46+
:param int sequence_retry_count: Number of retries to do if a SEQUENCE error occurs.
47+
When sending multiple send requsts on the same account, you can get SEQUENCE errors,
48+
This send method will automatically retry again
4349
4450
:returns: The dict returned from the result of the sent transaction.
4551
@@ -49,9 +55,26 @@ def send(self, transaction, account, language=None):
4955
if not isinstance(transaction, str):
5056
raise TypeError('The transaction must be a type str')
5157

52-
hash_data = self._transaction_prepare(account.address, transaction, language)
53-
signed_data = account.sign(hash_data['hash'])
54-
result = self._transaction_submit(account.address, hash_data['sequence_number'], hash_data['hash'], signed_data)
58+
# number of retries for a SEQUENCE error
59+
counter = 0
60+
last_sequence_number = None
61+
result = None
62+
last_id = None
63+
while sequence_retry_count >= 0:
64+
try:
65+
hash_data = self._transaction_prepare(account.address, transaction, last_sequence_number, language)
66+
signed_data = account.sign(hash_data['hash'])
67+
result = self._transaction_submit(account.address, hash_data['hash'], signed_data)
68+
except ConvexAPIError as error:
69+
if error.code == 'SEQUENCE':
70+
if sequence_retry_count == 0:
71+
raise
72+
sequence_retry_count -= 1
73+
time.sleep((secrets.randbelow(1000) + 1) / 1000)
74+
else:
75+
raise
76+
else:
77+
break
5578
return result
5679

5780
def query(self, transaction, address_account, language=None):
@@ -193,6 +216,7 @@ def get_account_info(self, address_account):
193216
:param Account, str address_account: Account or str address of an account to get current information on.
194217
:returns: dict of information, such as
195218
219+
.. code-block: json
196220
{
197221
"address": "7E66429CA9c10e68eFae2dCBF1804f0F6B3369c7164a3187D6233683c258710f",
198222
"is_library": false,
@@ -205,6 +229,7 @@ def get_account_info(self, address_account):
205229
"environment": {}
206230
}
207231
232+
208233
"""
209234
if isinstance(address_account, str):
210235
address = remove_0x_prefix(address_account)
@@ -222,7 +247,7 @@ def get_account_info(self, address_account):
222247
logger.debug(f'get_account_info repsonse {result}')
223248
return result
224249

225-
def _transaction_prepare(self, address, transaction, language=None):
250+
def _transaction_prepare(self, address, transaction, sequence_number=None, language=None):
226251
"""
227252
228253
"""
@@ -234,6 +259,8 @@ def _transaction_prepare(self, address, transaction, language=None):
234259
'lang': language,
235260
'source': transaction,
236261
}
262+
if sequence_number:
263+
data['sequence'] = sequence_number
237264
logger.debug(f'_transaction_prepare {prepare_url} {data}')
238265
response = requests.post(prepare_url, data=json.dumps(data))
239266
if response.status_code != 200:
@@ -246,14 +273,13 @@ def _transaction_prepare(self, address, transaction, language=None):
246273

247274
return result
248275

249-
def _transaction_submit(self, address, sequence_number, hash_data, signed_data):
276+
def _transaction_submit(self, address, hash_data, signed_data):
250277
"""
251278
252279
"""
253280
submit_url = urljoin(self._url, '/api/v1/transaction/submit')
254281
data = {
255282
'address': remove_0x_prefix(address),
256-
'sequence_number': sequence_number,
257283
'hash': hash_data,
258284
'sig': remove_0x_prefix(signed_data)
259285
}

tests/intergration/test_convex_multi_thread.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,17 @@ def process_on_convex(convex, test_account):
1616
values = []
1717
inc_values = []
1818
is_sent = False
19-
for index in range(secrets.randbelow(10) + 1):
20-
value = secrets.randbelow(1000)
21-
values.append(str(value))
22-
inc_values.append(value + 1)
23-
value_text = " ".join(values)
24-
while (not is_sent):
25-
try:
26-
result = convex.send(f'(map inc [{value_text}])', test_account)
27-
except ConvexAPIError as error:
28-
print('retrying again...')
29-
is_sent = False
30-
else:
31-
is_sent = True
32-
assert 'id' in result
33-
assert 'value' in result
34-
assert(result['value'] == inc_values)
19+
for counter in range(0, 4):
20+
for index in range(secrets.randbelow(10) + 1):
21+
value = secrets.randbelow(1000)
22+
values.append(str(value))
23+
inc_values.append(value + 1)
24+
value_text = " ".join(values)
25+
result = convex.send(f'(map inc [{value_text}])', test_account)
26+
assert(result)
27+
assert('id' in result)
28+
assert('value' in result)
29+
assert(result['value'] == inc_values)
3530

3631

3732
def test_convex_api_multi_thread(convex_url, test_account):

0 commit comments

Comments
 (0)