99import logging
1010from urllib .parse import urljoin
1111import requests
12+ import secrets
13+ import time
1214
1315
1416from 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 }
0 commit comments