diff --git a/README.md b/README.md index aa1eb37..7327c74 100644 --- a/README.md +++ b/README.md @@ -223,8 +223,8 @@ resp = transport.post_transaction( "DDvQqwqPXKd5P8dLAroFsnKR5Q3tKUtvnp", # RecipientAddress 1000000, # Amount "firstPassphrase", # First passphrase, mandatory - "vendorField", # Vendor field, optionnal - "secondPassphrase") # Second passphrase, optionnal + "vendorField", # Vendor field, optional + "secondPassphrase") # Second passphrase, optional ``` ## TODOS diff --git a/pythark/account.py b/pythark/account.py index 1ab73d5..d2310fd 100644 --- a/pythark/account.py +++ b/pythark/account.py @@ -12,7 +12,7 @@ def get_balance(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/accounts/getBalance", address=address) + resp = self.request('get', "api/accounts/getBalance", address=address) return resp.json() def get_public_key(self, address): @@ -21,7 +21,7 @@ def get_public_key(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/accounts/getPublickey", address=address) + resp = self.request('get', "api/accounts/getPublickey", address=address) return resp.json() def get_delegate_fee(self): @@ -29,17 +29,17 @@ def get_delegate_fee(self): :return: """ - resp = self.get("api/accounts/delegates/fee") + resp = self.request('get', "api/accounts/delegates/fee") return resp.json() def get_delegates(self, address, **kwargs): """ Get the delegates of an account. :param address: A valid Ark address. - :param kwargs: Optionnal parameters. orderBy, limit, offset + :param kwargs: Optional parameters. orderBy, limit, offset :return: """ - resp = self.get("api/accounts/delegates", address=address, **kwargs) + resp = self.request('get', "api/accounts/delegates", address=address, **kwargs) return resp.json() def get_accounts(self, address): @@ -48,14 +48,14 @@ def get_accounts(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/accounts", address=address) + resp = self.request('get', "api/accounts", address=address) return resp.json() def get_top_accounts(self, **kwargs): """ Get a list of top account - :param kwargs: Optionnal parameters. limit, offset + :param kwargs: Optional parameters. limit, offset :return: """ - resp = self.get("api/accounts/top", **kwargs) + resp = self.request('get', "api/accounts/top", **kwargs) return resp.json() diff --git a/pythark/api.py b/pythark/api.py index 1a8886f..b38c12c 100644 --- a/pythark/api.py +++ b/pythark/api.py @@ -1,15 +1,38 @@ import requests -import random -import json from retrying import retry -BASE_URL = "https://api.arknode.net/" # "http://37.59.129.164:4001/" -BASE_URL_DEV = "http://167.114.29.52:4002/" -BASE_URL_KAPUMAIN = "https://walletapi.kapu.one/" - -FALLBACKS_MAIN_ADDRESSES = [] -FALLBACKS_DEV_ADDRESSES = [] -FALLBACKS_KAPU_ADDRESSES = [] +NETWORKS = { + 'main': { + 'base_urls': [ + 'https://node1.arknet.cloud/' + ], + 'headers': { + 'nethash': '6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988', + 'version': '1.0.1', + 'port': '4001' + } + }, + 'dev': { + 'base_urls': [ + 'http://167.114.29.52:4002/' + ], + 'headers': { + 'nethash': '578e820911f24e039733b45e4882b73e301f813a0d2c31330dafda84534ffa23', + 'version': '1.1.1', + 'port': '4002' + } + }, + 'kapu': { + 'base_urls': [ + 'https://walletapi.kapu.one/' + ], + 'headers': { + 'nethash': '6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988', + 'version': '1.0.1', + 'port': '4001' + } + } +} class API: @@ -20,94 +43,26 @@ def __init__(self, network="main"): self.network = network @retry(stop_max_attempt_number=10, wait_fixed=10000) - def get(self, endpoint, **kwargs): - """ Do a HTTP get request to a specified endpoint (with optionnal parameters). + def request(self, req_type, endpoint, **kwargs): + """ Do a HTTP request to a specified endpoint (with optional parameters). + :param req_type: The request type. Either `get` or `post`. :param endpoint: The endpoint we want to reach. - :param kwargs: Optionnal parameters of the query. + :param kwargs: Optional parameters of the query. :return: Request response if HTTP code is equal to 200. """ payload = {name: kwargs[name] for name in kwargs if kwargs[name] is not None} - try: - if self.network == "main": - headers_main = get_main_network_headers() - r = requests.get("{0}{1}".format(BASE_URL, endpoint), headers=headers_main, params=payload, timeout=10) - if self.network == "dark" or self.network == "dev": - headers_dev = get_dev_network_headers() - r = requests.get("{0}{1}".format(BASE_URL_DEV, endpoint), headers=headers_dev, params=payload, timeout=10) - if self.network == "kapu": - headers_kapu_main = get_kapu_main_network_headers() - r = requests.get("{0}{1}".format(BASE_URL_KAPUMAIN, endpoint), headers=headers_kapu_main, params=payload, timeout=10) - if r.status_code == 200: - return r - except requests.exceptions.Timeout: - if self.network == "dark" or self.network == "dev": - populate_fallback(FALLBACKS_DEV_ADDRESSES, self.network) - url = select_random_ip(FALLBACKS_DEV_ADDRESSES) + "/" - r = requests.get("{0}{1}".format(url, endpoint), headers=headers_dev, params=payload, timeout=10) - elif self.network == "kapu": - populate_fallback(FALLBACKS_KAPU_ADDRESSES, self.network) - url = select_random_ip(FALLBACKS_KAPU_ADDRESSES) + "/" - r = requests.get("{0}{1}".format(url, endpoint), headers=headers_kapu_main, params=payload, timeout=10) - else: - populate_fallback(FALLBACKS_MAIN_ADDRESSES, self.network) - url = select_random_ip(FALLBACKS_MAIN_ADDRESSES) + "/" - r = requests.get("{0}{1}".format(url, endpoint), headers=headers_main, params=payload, timeout=10) - if r.status_code == 200: - return r - except requests.exceptions.ConnectionError as e: - print("Connection error : ", e) - except requests.exceptions.ReadTimeout as e: - print("ReadTimeOut error : ", e) - - def post(self, endpoint, **kwargs): - payload = {name: kwargs[name] for name in kwargs if kwargs[name] is not None} - r = requests.post("{0}{1}".format(BASE_URL, endpoint), headers=get_dev_network_headers(), params=payload) - return r - - -def get_main_network_headers(): - headers = { - "nethash": "6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988", - "version": "1.0.1", - "port": "4001" - } - return headers - - -def get_dev_network_headers(): - headers = { - "nethash": "578e820911f24e039733b45e4882b73e301f813a0d2c31330dafda84534ffa23", - "version": "1.1.1", - "port": "4002" - } - return headers - - -def get_kapu_main_network_headers(): - headers = { - "nethash": "6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988", - "version": "1.0.1", - "port": "4001" - } - return headers - - -def populate_fallback(fallback, network): - from . import Peer - if network == 'dev': - p = Peer("dev") - elif network == 'kapu': - p = Peer("kapu") - else: - p = Peer() - r = p.get_peers() - for peer in r["peers"]: - if peer["delay"] <= 50: - fallback.append(peer) - return fallback - - -def select_random_ip(fallback): - rand = random.choice(fallback) - return rand['ip'] + headers = NETWORKS[self.network]['headers'] + for i, base_url in enumerate(NETWORKS[self.network]['base_urls']): + try: + if req_type == 'post': + r = requests.post(base_url + endpoint, headers=headers, params=payload, timeout=10) + elif req_type == 'get': + r = requests.get(base_url + endpoint, headers=headers, params=payload, timeout=10) + else: + raise ValueError('Invalid request type: ' + req_type) + if r.status_code == 200: + return r + except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: + print("URL #{} failed: {}".format(i + 1, e)) + print('Failed to process {} request'.format(req_type)) diff --git a/pythark/block.py b/pythark/block.py index 407800e..c4da3d1 100644 --- a/pythark/block.py +++ b/pythark/block.py @@ -12,17 +12,17 @@ def get_block(self, id): :param id: Valid Block ID. :return: """ - resp = self.get("api/blocks/get", id=id) + resp = self.request('get', "api/blocks/get", id=id) return resp.json() def get_blocks(self, **kwargs): """ Get all blocks. - :param kwargs: Optionnal parameters. limit, orderBy, offset, generatorPublicKey, totalAmount, totalFee, reward, + :param kwargs: Optional parameters. limit, orderBy, offset, generatorPublicKey, totalAmount, totalFee, reward, previousBlock, height :return: """ - resp = self.get("api/blocks", **kwargs) + resp = self.request('get', "api/blocks", **kwargs) return resp.json() def get_height(self): @@ -30,7 +30,7 @@ def get_height(self): :return: """ - resp = self.get("api/blocks/getHeight") + resp = self.request('get', "api/blocks/getHeight") return resp.json() def get_epoch(self): @@ -38,7 +38,7 @@ def get_epoch(self): :return: """ - resp = self.get("api/blocks/getEpoch") + resp = self.request('get', "api/blocks/getEpoch") return resp.json() def get_nethash(self): @@ -46,7 +46,7 @@ def get_nethash(self): :return: """ - resp = self.get("api/blocks/getNethash") + resp = self.request('get', "api/blocks/getNethash") return resp.json() def get_fee(self): @@ -54,7 +54,7 @@ def get_fee(self): :return: """ - resp = self.get("api/blocks/getFee") + resp = self.request('get', "api/blocks/getFee") return resp.json() def get_fees(self): @@ -62,7 +62,7 @@ def get_fees(self): :return: """ - resp = self.get("api/blocks/getFees") + resp = self.request('get', "api/blocks/getFees") return resp.json() def get_milestone(self): @@ -70,7 +70,7 @@ def get_milestone(self): :return: """ - resp = self.get("api/blocks/getMilestone") + resp = self.request('get', "api/blocks/getMilestone") return resp.json() def get_reward(self): @@ -78,7 +78,7 @@ def get_reward(self): :return: """ - resp = self.get("api/blocks/getReward") + resp = self.request('get', "api/blocks/getReward") return resp.json() def get_supply(self): @@ -86,7 +86,7 @@ def get_supply(self): :return: """ - resp = self.get("api/blocks/getSupply") + resp = self.request('get', "api/blocks/getSupply") return resp.json() def get_status(self): @@ -94,5 +94,5 @@ def get_status(self): :return: """ - resp = self.get("api/blocks/getStatus") + resp = self.request('get', "api/blocks/getStatus") return resp.json() diff --git a/pythark/delegate.py b/pythark/delegate.py index d093de8..f519021 100644 --- a/pythark/delegate.py +++ b/pythark/delegate.py @@ -12,17 +12,17 @@ def get_delegates_count(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/delegates/count", address=address) + resp = self.request('get', "api/delegates/count", address=address) return resp.json() def search_delegates(self, query, **kwargs): """ Search for specific delegates. :param query: The name we want to search. - :param kwargs: Optionnal parameters. limit + :param kwargs: Optional parameters. limit :return: """ - resp = self.get("api/delegates/search", q=query, **kwargs) + resp = self.request('get', "api/delegates/search", q=query, **kwargs) return resp.json() def get_voters(self, publicKey): @@ -31,7 +31,7 @@ def get_voters(self, publicKey): :param publicKey: A valid Ark publicKey. :return: """ - resp = self.get("api/delegates/voters", publicKey=publicKey) + resp = self.request('get', "api/delegates/voters", publicKey=publicKey) return resp.json() def get_delegate(self, username): @@ -40,7 +40,7 @@ def get_delegate(self, username): :param username: The delegate's name. :return: """ - resp = self.get("api/delegates/get", username=username) + resp = self.request('get', "api/delegates/get", username=username) return resp.json() def get_delegate_publickey(self, publicKey): @@ -49,16 +49,16 @@ def get_delegate_publickey(self, publicKey): :param publicKey: A valid Ark publicKey. :return: """ - resp = self.get("api/delegates/get", publicKey=publicKey) + resp = self.request('get', "api/delegates/get", publicKey=publicKey) return resp.json() def get_delegates(self, **kwargs): """ Get all delegates. - :param kwargs: Optionnal parameters. orderBy, limit, offset. + :param kwargs: Optional parameters. orderBy, limit, offset. :return: """ - resp = self.get("api/delegates", **kwargs) + resp = self.request('get', "api/delegates", **kwargs) return resp.json() def get_delegate_fee(self, address): @@ -67,7 +67,7 @@ def get_delegate_fee(self, address): :param address: :return: """ - resp = self.get("api/delegates/fee", address=address) + resp = self.request('get', "api/delegates/fee", address=address) return resp.json() def get_forged_by_account(self, generatorPublicKey): @@ -76,7 +76,7 @@ def get_forged_by_account(self, generatorPublicKey): :param generatorPublicKey: A valid Ark generatorPublicKey. :return: """ - resp = self.get("api/delegates/forging/getForgedByAccount", generatorPublicKey=generatorPublicKey) + resp = self.request('get', "api/delegates/forging/getForgedByAccount", generatorPublicKey=generatorPublicKey) return resp.json() def get_next_forgers(self, address): @@ -85,5 +85,5 @@ def get_next_forgers(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/delegates/getNextForgers", address=address) + resp = self.request('get', "api/delegates/getNextForgers", address=address) return resp.json() diff --git a/pythark/loader.py b/pythark/loader.py index 4252450..e86c3cd 100644 --- a/pythark/loader.py +++ b/pythark/loader.py @@ -13,7 +13,7 @@ def get_status(self): :return: """ - resp = self.get("api/loader/status") + resp = self.request('get', "api/loader/status") return resp.json() def get_sync(self): @@ -21,7 +21,7 @@ def get_sync(self): :return: """ - resp = self.get("api/loader/status/sync") + resp = self.request('get', "api/loader/status/sync") return resp.json() def autoconfigure(self): @@ -29,5 +29,5 @@ def autoconfigure(self): :return: """ - resp = self.get("api/loader/autoconfigure") + resp = self.request('get', "api/loader/autoconfigure") return resp.json() \ No newline at end of file diff --git a/pythark/multisignature.py b/pythark/multisignature.py index b516444..fdff107 100644 --- a/pythark/multisignature.py +++ b/pythark/multisignature.py @@ -12,7 +12,7 @@ def get_pending(self, publicKey): :param publicKey: A valid Ark publicKey. :return: """ - resp = self.get("api/multisignatures/pending", publicKey=publicKey) + resp = self.request('get', "api/multisignatures/pending", publicKey=publicKey) return resp.json() def get_accounts(self, publicKey): @@ -22,5 +22,5 @@ def get_accounts(self, publicKey): :param publicKey: A valid Ark publicKey. :return: """ - resp = self.get("api/multisignatures/accounts", publicKey=publicKey) + resp = self.request('get', "api/multisignatures/accounts", publicKey=publicKey) return resp.json() diff --git a/pythark/peer.py b/pythark/peer.py index 1bd951b..7012aa6 100644 --- a/pythark/peer.py +++ b/pythark/peer.py @@ -13,7 +13,7 @@ def get_peer(self, ip, port): :param port: Valid port of the peer. :return: """ - resp = self.get("api/peers/get", ip=ip, port=port) + resp = self.request('get', "api/peers/get", ip=ip, port=port) return resp.json() def get_peers(self): @@ -21,7 +21,7 @@ def get_peers(self): :return: """ - resp = self.get("api/peers") + resp = self.request('get', "api/peers") return resp.json() def get_peer_version(self): @@ -29,5 +29,5 @@ def get_peer_version(self): :return: """ - resp = self.get("api/peers/version") + resp = self.request('get', "api/peers/version") return resp.json() diff --git a/pythark/signature.py b/pythark/signature.py index d0d22a4..1a9b7a4 100644 --- a/pythark/signature.py +++ b/pythark/signature.py @@ -11,7 +11,7 @@ def get_signature_fee(self): :return: """ - resp = self.get("api/signatures/fee") + resp = self.request('get', "api/signatures/fee") return resp.json() def get_address_signature_fee(self, address): @@ -20,5 +20,5 @@ def get_address_signature_fee(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("api/signatures/fee", address=address) + resp = self.request('get', "api/signatures/fee", address=address) return resp.json() diff --git a/pythark/transaction.py b/pythark/transaction.py index f07d4a5..d64aca5 100644 --- a/pythark/transaction.py +++ b/pythark/transaction.py @@ -12,17 +12,17 @@ def get_transaction(self, id): :param id: A valid Transaction id. :return: """ - resp = self.get("api/transactions/get", id=id) + resp = self.request('get', "api/transactions/get", id=id) return resp.json() def get_transactions(self, **kwargs): """ Get all transactions. - :param kwargs: Optionnal parameters. blockId, limit, orderBy, offset, senderPublicKey, vendorField, ownerPublicKey, + :param kwargs: Optional parameters. blockId, limit, orderBy, offset, senderPublicKey, vendorField, ownerPublicKey, ownerAddress, senderId, recipientId, amount, fee :return: """ - resp = self.get("api/transactions", **kwargs) + resp = self.request('get', "api/transactions", **kwargs) return resp.json() def get_unconfirmed_transaction(self, id): @@ -31,14 +31,14 @@ def get_unconfirmed_transaction(self, id): :param id: A valid Transaction id. :return: """ - resp = self.get("api/transactions/unconfirmed/get", id=id) + resp = self.request('get', "api/transactions/unconfirmed/get", id=id) return resp.json() def get_unconfirmed_transactions(self, **kwargs): """ Get all unconfirmed transactions. - :param kwargs: Optionnal parameters. senderPublicKey, address + :param kwargs: Optional parameters. senderPublicKey, address :return: """ - resp = self.get("api/transactions/unconfirmed", **kwargs) + resp = self.request('get', "api/transactions/unconfirmed", **kwargs) return resp.json() \ No newline at end of file diff --git a/pythark/transport.py b/pythark/transport.py index 25c11d9..64a590c 100644 --- a/pythark/transport.py +++ b/pythark/transport.py @@ -19,7 +19,7 @@ def get_peers(self): :return: """ - resp = self.get("peer/list") + resp = self.request('get', "peer/list") return resp.json() def get_common_blocks(self, ids): @@ -28,7 +28,7 @@ def get_common_blocks(self, ids): :param ids: List of Block ids. :return: """ - resp = self.get("peer/blocks/common", ids=','.join(ids)) + resp = self.request('get', "peer/blocks/common", ids=','.join(ids)) return resp.json() def get_blocks(self, address): @@ -37,7 +37,7 @@ def get_blocks(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("peer/blocks", address=address) + resp = self.request('get', "peer/blocks", address=address) return resp.json() def get_block(self, address): @@ -47,7 +47,7 @@ def get_block(self, address): :param address: A valid Ark address. :return: """ - resp = self.get("peer/block", address=address) + resp = self.request('get', "peer/block", address=address) return resp.json() def get_transactions(self): @@ -55,7 +55,7 @@ def get_transactions(self): :return: """ - resp = self.get("peer/transactions") + resp = self.request('get', "peer/transactions") return resp.json() def post_transaction(self, network, recipientId, amount, secret, vendorField="", secondSecret=""): @@ -65,8 +65,8 @@ def post_transaction(self, network, recipientId, amount, secret, vendorField="", :param recipientId: A valid Ark address. :param amount: Amount of currency we want to transfer. :param secret: BIP39 seedpass. - :param vendorField: Optionnal vendorField. - :param secondSecret: Optionnal BIP39 second seedpass. + :param vendorField: Optional vendorField. + :param secondSecret: Optional BIP39 second seedpass. :return: """ rest.use(network) @@ -77,7 +77,7 @@ def post_transaction(self, network, recipientId, amount, secret, vendorField="", def post_transaction_bis(self, recipientId, amount, secret, secondSecret="", vendorField=None): transactions = [] - resp = self.post("peer/transactions", recipientId=recipientId, amount=amount, secret=secret, secondSecret=secondSecret, vendorField=vendorField) + resp = self.request('post', "peer/transactions", recipientId=recipientId, amount=amount, secret=secret, secondSecret=secondSecret, vendorField=vendorField) return resp.json() def get_transactions_from_ids(self, ids): @@ -86,7 +86,7 @@ def get_transactions_from_ids(self, ids): :param ids: A list of valid Transaction id :return: """ - resp = self.get("peer/transactionsFromIds", ids=','.join(ids)) + resp = self.request('get', "peer/transactionsFromIds", ids=','.join(ids)) return resp.json() def get_height(self): @@ -94,7 +94,7 @@ def get_height(self): :return: """ - resp = self.get("peer/height") + resp = self.request('get', "peer/height") return resp.json() def get_status(self): @@ -102,5 +102,5 @@ def get_status(self): :return: """ - resp = self.get("peer/status") + resp = self.request('get', "peer/status") return resp.json() \ No newline at end of file