Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix handle 429 timeout #14

Merged
merged 2 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 77 additions & 71 deletions tools/flat-distributor/flat-distributor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,32 +120,6 @@ def parse_sig(log):
return 'Error parsing signature - check the detailed logs.'


class TransferCmd:
def __init__(self, cmd, instruction, mint_address, decimals, drop_amount, recipient, url, options=None):
self.cmd = cmd
self.instruction = instruction
self.mint_address = mint_address
self.decimals = decimals
self.drop_amount = drop_amount
self.recipient = recipient
self.url = url
if options is None:
self.options = []
else:
self.options = options

def to_str(self):
return f"{self.cmd} {self.instruction} {self.mint_address} {self.drop_amount:.{self.decimals}f} {self.recipient} {' '.join(self.options)}"

def to_list(self):
#obj = [self.cmd, self.instruction, self.mint_address, str(self.drop_amount), self.recipient]
obj = [self.cmd, self.instruction, self.mint_address,
f"{self.drop_amount:.{self.decimals}f}", self.recipient, '--url', self.url]
if self.options:
obj.extend(self.options)
return obj


def run(cmd):
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
Expand All @@ -171,18 +145,18 @@ def try_transfer(cmd, addr, drop, log_success, log_unconfirmed, log_failed,
break
else:
err_msg = err.decode('utf-8')
if TOO_MANY_REQUESTS in err_msg:
print('429, waiting 5... ', end='', flush=True)
time.sleep(5)
log_detail_entry += err_msg + '\n'
continue
if RPC_ERROR in err_msg:
print('-32005 RPC Error, waiting 5... ',
end='', flush=True)
log_detail_entry += err_msg + '\n'
time.sleep(5)
continue
if UNCONFIRMED in err_msg:
if RETRY_ON_429 and (TOO_MANY_REQUESTS in err_msg):
print('429, waiting 5... ', end='', flush=True)
time.sleep(5)
log_detail_entry += err_msg + '\n'
continue
if UNCONFIRMED in err_msg or TOO_MANY_REQUESTS in err_msg:
print(
f'{bcolors.DANGER}UNCONFIRMED{bcolors.ENDC}', flush=True)
with open(log_unconfirmed, "a") as lu:
Expand Down Expand Up @@ -239,6 +213,32 @@ def get_balance(addr, addr_type, mint, url):
return False, 'Could not find token account'


class TransferCmd:
def __init__(self, cmd, instruction, mint_address, decimals, drop_amount, recipient, url, options=None):
self.cmd = cmd
self.instruction = instruction
self.mint_address = mint_address
self.decimals = decimals
self.drop_amount = drop_amount
self.recipient = recipient
self.url = url
if options is None:
self.options = []
else:
self.options = options

def to_str(self):
return f"{self.cmd} {self.instruction} {self.mint_address} {self.drop_amount:.{self.decimals}f} {self.recipient} {' '.join(self.options)}"

def to_list(self):
#obj = [self.cmd, self.instruction, self.mint_address, str(self.drop_amount), self.recipient]
obj = [self.cmd, self.instruction, self.mint_address,
f"{self.drop_amount:.{self.decimals}f}", self.recipient, '--url', self.url]
if self.options:
obj.extend(self.options)
return obj


class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
Expand All @@ -253,6 +253,7 @@ class bcolors:


def main():
global TOKEN_MINT, TOKEN_DECIMALS, RPC_URL, LOG_FOLDER_PREFIX, FULL_LOGS, SUCCESS_LOGS, FAILED_LOGS, CANCELED_LOGS, UNCONFIRMED_LOGS, RETRY_ON_429
args = parser.parse_args()
mode = args.mode
if not mode:
Expand All @@ -273,17 +274,6 @@ def main():
except KeyError as e:
sys.exit('Error reading config file: ' + str(e))
else:
# Using default values for logs
TOKEN_MINT = ""
TOKEN_DECIMALS = ""
RPC_URL = ""
LOG_FOLDER_PREFIX = 'logs-'
FULL_LOGS = 'detailed.log'
SUCCESS_LOGS = 'success.log'
FAILED_LOGS = 'failed.log'
CANCELED_LOGS = 'canceled.log'
UNCONFIRMED_LOGS = 'unconfirmed.log'

if RPC_URL == "":
rpc_endpoints = {
'mainnet': 'https://api.mainnet-beta.solana.com',
Expand All @@ -303,28 +293,25 @@ def main():
input_file = args.file_name
address_type = args.address_type
drop = args.drop
before(input_file, drop, address_type,
TOKEN_MINT, TOKEN_DECIMALS, RPC_URL)
before(input_file, drop, address_type)
elif mode == 'check-after':
before_file = args.before_file_name
addr_type = args.address_type
after(before_file, addr_type, TOKEN_MINT, TOKEN_DECIMALS, RPC_URL)
after(before_file, addr_type)
elif mode == 'transfer':
input_path = args.address_list
interactive = args.interactive
drop_amount = args.drop_amount
fund_recipient = args.fund_recipient
allow_unfunded_recipient = args.allow_unfunded_recipient
RETRY_ON_429 = args.retry_on_429
transfer(input_path, interactive,drop_amount,
fund_recipient, allow_unfunded_recipient,
TOKEN_MINT, TOKEN_DECIMALS,RPC_URL,
LOG_FOLDER_PREFIX, FULL_LOGS,
SUCCESS_LOGS, FAILED_LOGS, CANCELED_LOGS,
UNCONFIRMED_LOGS
fund_recipient, allow_unfunded_recipient
)


def before(input_file, drop, addr_type, mint, decimals, rpc_url):
def before(input_file, drop, addr_type):
global TOKEN_MINT, TOKEN_DECIMALS, RPC_URL
output_file = './before.csv'
print('recipient,current-balance,expected-balance')

Expand All @@ -336,19 +323,20 @@ def before(input_file, drop, addr_type, mint, decimals, rpc_url):
for line in lines:
try:
addr = line.strip()
ok, balance = get_balance(addr, addr_type, mint, rpc_url)
ok, balance = get_balance(addr, addr_type, TOKEN_MINT, RPC_URL)
except (IndexError, ValueError) as e:
sys.exit('Error when reading input file: ' + str(e))
if ok:
expected = float(balance) + drop
print(f'{addr} - {balance:.3f} - {expected:.3f}')
fw.write(f'{addr},{balance:.{decimals}f},{expected:.{decimals}f}\n')
fw.write(f'{addr},{balance:.{TOKEN_DECIMALS}f},{expected:.{TOKEN_DECIMALS}f}\n')
else:
print(f'{addr} - No token account - No token account')
fw.write(f'{addr},No token account,No token account\n')


def after(input_file, addr_type, mint, decimals, url):
def after(input_file, addr_type):
global TOKEN_MINT, TOKEN_DECIMALS, RPC_URL
lines = []
output_file = './after.csv'
print('recipient,expected-balance,actual-balance,difference')
Expand All @@ -367,12 +355,12 @@ def after(input_file, addr_type, mint, decimals, url):

try:
expected = float(expected)
output_line += f'{expected:.{decimals}f},'
output_line += f'{expected:.{TOKEN_DECIMALS}f},'
except ValueError:
# Not a number, expecting a No token account message
output_line += f'{expected},'

ok, actual = get_balance(addr, addr_type, mint, url)
ok, actual = get_balance(addr, addr_type, TOKEN_MINT, RPC_URL)
if ok:
endc = '\033[0m'
startc = ''
Expand All @@ -382,7 +370,7 @@ def after(input_file, addr_type, mint, decimals, url):
startc = '\033[92m'
else:
startc = '\033[91m'
output_line += f'{actual:.{decimals}f},{diff:.{decimals}f}'
output_line += f'{actual:.{TOKEN_DECIMALS}f},{diff:.{TOKEN_DECIMALS}f}'
except TypeError:
# Assuming actual was not a number
diff = 'NaN'
Expand All @@ -395,9 +383,8 @@ def after(input_file, addr_type, mint, decimals, url):


def transfer(input_path, interactive, drop_amount,
fund_recipient, allow_unfunded_recipient, mint,
decimals, rpc_url, log_prefix, full_log, success_log,
failed_log, canceled_log, unconfirmed_log):
fund_recipient, allow_unfunded_recipient):
global TOKEN_MINT, TOKEN_DECIMALS, RPC_URL, LOG_FOLDER_PREFIX, FULL_LOGS, SUCCESS_LOGS, FAILED_LOGS, CANCELED_LOGS, UNCONFIRMED_LOGS
SEPARATOR = "-" * 50
LOG_SEPARATOR = "-" * 30 + "\n"
TOO_MANY_REQUESTS = "429 Too Many Requests"
Expand All @@ -412,10 +399,10 @@ def transfer(input_path, interactive, drop_amount,

print(f"{bcolors.DANGER}WARNING: MAKE SURE YOU ARE USING THE CORRECT WALLET/SUPPLY/ TO DISTRIBUTE.\nYOUR CURRENT WALLET ADDRESS IS: {current_supply.decode('utf-8')}{bcolors.ENDC}")
print(
f"Running airdrop for the Token Mint: {bcolors.OKGREEN}{mint}{bcolors.ENDC}")
f"Running airdrop for the Token Mint: {bcolors.OKGREEN}{TOKEN_MINT}{bcolors.ENDC}")
drop = amount_prompt(drop_amount)
print(
f"Airdrop amount: {bcolors.OKGREEN}{drop:,.{decimals}f}{bcolors.ENDC}")
f"Airdrop amount: {bcolors.OKGREEN}{drop:,.{TOKEN_DECIMALS}f}{bcolors.ENDC}")

try:
with open(input_path) as f:
Expand All @@ -427,16 +414,16 @@ def transfer(input_path, interactive, drop_amount,

# region Create log files, print locations, write headers
timestamp = get_current_utc_time_str()
log_success = gen_logfile(success_log, timestamp, log_prefix)
log_canceled = gen_logfile(canceled_log, timestamp, log_prefix)
log_failed = gen_logfile(failed_log, timestamp, log_prefix)
log_unconfirmed = gen_logfile(unconfirmed_log, timestamp, log_prefix)
log_full = gen_logfile(full_log, timestamp, log_prefix)
log_success = gen_logfile(SUCCESS_LOGS, timestamp, LOG_FOLDER_PREFIX)
log_canceled = gen_logfile(CANCELED_LOGS, timestamp, LOG_FOLDER_PREFIX)
log_failed = gen_logfile(FAILED_LOGS, timestamp, LOG_FOLDER_PREFIX)
log_unconfirmed = gen_logfile(UNCONFIRMED_LOGS, timestamp, LOG_FOLDER_PREFIX)
log_full = gen_logfile(FULL_LOGS, timestamp, LOG_FOLDER_PREFIX)

print(f" Successful logs: (tail -f {log_success})")
print(f" Canceled logs: (tail -f {log_canceled})")
print(f" Failed logs: (tail -f {log_failed})")
print(f" Unconfirmed logs: (tail -f {log_unconfirmed}")
print(f" Unconfirmed logs: (tail -f {log_unconfirmed})")
print(f" Detailed logs: (tail -f {log_full})")

with open(log_success, "a") as ls:
Expand All @@ -462,7 +449,7 @@ def transfer(input_path, interactive, drop_amount,
if allow_unfunded_recipient:
options.append('--allow-unfunded-recipient')
cmd = TransferCmd("spl-token", "transfer",
mint, decimals, drop, addr, rpc_url, options)
TOKEN_MINT, TOKEN_DECIMALS, drop, addr, RPC_URL, options)
if not interactive:
log_detail_entry = ''
print(f"{i+1}. Airdrop to {addr}: ", end="", flush=True)
Expand All @@ -483,7 +470,7 @@ def transfer(input_path, interactive, drop_amount,
log_detail_entry += f"{i+1}. Cmdline: {cmd.to_str()}\n"

confirm, switch_mode = single_transaction_prompt(
cmd.to_str(), drop, addr, decimals)
cmd.to_str(), drop, addr, TOKEN_DECIMALS)
if switch_mode:
print("Switching to non-interactive mode.")
interactive = False
Expand Down Expand Up @@ -620,6 +607,25 @@ def transfer(input_path, interactive, drop_amount,
required=False,
help='Complete the transfer even if the recipient\'s address is not funded.'
)
parser_t.add_argument(
'--retry-on-429',
dest='retry_on_429',
action='store_true',
default=False,
required=False,
help='Retry when a HTTP 429 error code is encountered. Use this at your own risk.'
)
#endregion

if __name__ == '__main__':
TOKEN_MINT = ""
TOKEN_DECIMALS = ""
RPC_URL = ""
LOG_FOLDER_PREFIX = 'logs-'
FULL_LOGS = 'detailed.log'
SUCCESS_LOGS = 'success.log'
FAILED_LOGS = 'failed.log'
CANCELED_LOGS = 'canceled.log'
UNCONFIRMED_LOGS = 'unconfirmed.log'
RETRY_ON_429 = False
main()
Loading