github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/tools/airdrop-setup/airdrop-setup.py (about)

     1  #!/usr/bin/python3
     2  """
     3  Test script to be used for creating local accounts to test the airdrop. Note that this will only run against the local
     4  keybase dev server since it uses the `keybase signup --batch` flag and relies on a dev only invite code.
     5  
     6  Run via `python3 airdrop-setup.py out.json 1 2 3` in order to create:
     7  - 1 account that has not accepted the disclaimer
     8  - 2 accounts that have accepted the stellar disclaimer
     9  - 3 accounts that have a starting balance
    10  Data will be written to out.json in the form:
    11  
    12  ```
    13  {
    14      'no_disclaimer': ['user1'],
    15      'accepted_disclaimer': ['user2', 'user3'],
    16      'with_balance': ['user4', 'user5'],
    17  }
    18  ```
    19  """
    20  
    21  import json
    22  import os
    23  from random import SystemRandom
    24  from multiprocessing import Pool
    25  import signal
    26  import string
    27  import subprocess
    28  import sys
    29  import time
    30  
    31  import requests
    32  
    33  # The maximum number of times we will retry if something goes wrong
    34  RETRY_COUNT = 5
    35  
    36  def compile():
    37      # Compile dev keybase
    38      print("Compiling keybase...")
    39      os.system("go install -tags devel github.com/keybase/client/go/keybase")
    40  
    41  def secure_random(n):
    42      return ''.join([SystemRandom().choice(string.ascii_lowercase) for _ in range(n)])
    43  
    44  def start_service(home):
    45      proc = subprocess.Popen(f"$GOPATH/bin/keybase --home {home} service", stdout=subprocess.PIPE,
    46                                shell=True, preexec_fn=os.setsid)
    47      while True:
    48          if os.path.exists(home + "/.config/keybase.devel/keybased.sock"):
    49              break
    50          time.sleep(0.1)
    51      return proc
    52  
    53  def kill_service(home, proc):
    54      os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
    55      os.system(f"rm -r {home} 2>&1 > /dev/null")
    56  
    57  def create_user(acceptDisclaimer=False, initBalance=False, retryCnt=0, *_):
    58      username = secure_random(16)
    59      password = secure_random(64)
    60      home = f"/tmp/airdrop-setup-{secure_random(32)}"
    61      proc = start_service(home)
    62  
    63      try:
    64          # This is a special dev only invite code that can be used repeatedly
    65          os.system(f"$GOPATH/bin/keybase --home {home} signup -batch --username {username} --passphrase {password} --no-email --invite-code 202020202020202020202020")
    66          if acceptDisclaimer or initBalance:
    67              output = subprocess.check_output(""" echo '{"method": "setup-wallet"}' | $GOPATH/bin/keybase --home %s wallet api """ % home, shell=True)
    68              assert b"disclaimer" in output, output
    69  
    70          if initBalance:
    71              api_ret = json.loads(subprocess.check_output(""" echo '{"method": "lookup", "params": {"options": {"name": "%s"}}}' | $GOPATH/bin/keybase --home %s wallet api """ % (username, home), shell=True))
    72              address = api_ret['result']['accountID']
    73              assert b"transaction" in requests.get(f"https://friendbot.stellar.org/?addr={address}").content
    74      except Exception as e:
    75          # If something goes wrong, just recur up to RETRY_COUNT times
    76          if retryCnt > RETRY_COUNT:
    77              raise e
    78          return create_user(acceptDisclaimer=acceptDisclaimer, initBalance=initBalance, retryCnt=retryCnt+1)
    79      finally:
    80          kill_service(home, proc)
    81  
    82      return username
    83  
    84  def create_user_with_disclaimer(*_):
    85      return create_user(acceptDisclaimer=True)
    86  
    87  def create_user_with_balance(*_):
    88      return create_user(initBalance=True)
    89  
    90  if __name__ == '__main__':
    91      if len(sys.argv) != 5:
    92          print("Usage: `python3 airdrop-setup.py out.json X Y Z` where X is the number of users who have not accepted the disclaimer, Y is the number that have accepted the disclaimer, Z is the number that have a balance")
    93          exit(2)
    94      compile()
    95      # The number of processes to use in parallel. This can be adjusted based off of your system.
    96      p = Pool(16)
    97      print("Creating users without the disclaimer...")
    98      no_disclaimer = p.map(create_user, range(int(sys.argv[2])))
    99      print("Creating users with the disclaimer...")
   100      accepted_disclaimer = p.map(create_user_with_disclaimer, range(int(sys.argv[3])))
   101      print("Creating users with a testnet balance...")
   102      with_balance = p.map(create_user_with_balance, range(int(sys.argv[4])))
   103      print("Done! Writing to %s" % sys.argv[1])
   104      with open(sys.argv[1], 'w+') as f:
   105          f.write(json.dumps({
   106              'no_disclaimer': no_disclaimer,
   107              'accepted_disclaimer': accepted_disclaimer,
   108              'with_balance': with_balance,
   109          }))