chainlib-eth

Ethereum implementation of the chainlib interface
Info | Log | Files | Refs | README | LICENSE

settings.py (5717B)


      1 # standard imports
      2 import logging
      3 
      4 # external imports
      5 from chainlib.settings import process_settings as base_process_settings
      6 from chainlib.error import SignerMissingException
      7 from hexathon import (
      8         add_0x,
      9         strip_0x,
     10         )
     11 from chainlib.block import BlockSpec
     12 
     13 # local imports
     14 import chainlib.eth.cli
     15 from chainlib.eth.address import to_checksum_address
     16 from chainlib.eth.constant import ZERO_ADDRESS
     17 
     18 logg = logging.getLogger(__name__)
     19 
     20 
     21 def process_settings_rpc(settings, config):
     22     rpc = chainlib.eth.cli.Rpc(settings.get('WALLET'))
     23     conn = rpc.connect_by_config(config, nonce_confirmed=True)
     24 
     25     settings.set('CONN', conn)
     26     settings.set('RPC_ID_GENERATOR', rpc.id_generator)
     27     settings.set('RPC_SEND', config.true('_RPC_SEND'))
     28     settings.set('WAIT', config.true('_WAIT'))
     29 
     30     gas_oracle = rpc.get_gas_oracle()
     31     settings.set('GAS_ORACLE', gas_oracle)
     32     settings.set('FEE_ORACLE', gas_oracle)
     33 
     34     sender_address = rpc.get_sender_address()
     35     try:
     36         settings.set('SIGNER', rpc.get_signer())
     37     except AttributeError:
     38         pass
     39     except SignerMissingException:
     40         pass
     41 
     42     settings.set('SENDER_ADDRESS', add_0x(sender_address))
     43 
     44     nonce_oracle = rpc.get_nonce_oracle()
     45     settings.set('NONCE_ORACLE', nonce_oracle)
     46 
     47     return settings
     48 
     49 
     50 def process_settings_blockspec(settings, config):
     51     blockspec_in = None
     52     try:
     53         blockspec_in = config.get('_HEIGHT')
     54     except KeyError:
     55         return settings
     56 
     57     blockspec = None
     58     if blockspec_in == 'latest':
     59         blockspec = BlockSpec.LATEST
     60     elif blockspec_in == 'pending':
     61         blockspec = BlockSpec.PENDING
     62     else:
     63         blockspec = int(blockspec_in)
     64 
     65     settings.set('HEIGHT', blockspec)
     66 
     67     return settings
     68 
     69 
     70 def __try_zero_address(config, address):
     71     try:
     72         if int(address) == 0:
     73             return ZERO_ADDRESS
     74     except ValueError:
     75         pass
     76 
     77     try:
     78         if int(address, 16) == 0:
     79             return ZERO_ADDRESS
     80     except ValueError:
     81         pass
     82 
     83     recipient = to_checksum_address(address)
     84     if not config.true('_UNSAFE') and recipient != address:
     85         raise ValueError('invalid checksum address: {}'.format(address))
     86 
     87     return add_0x(recipient)
     88 
     89 
     90 def __calculate_net_amount(settings, config):
     91     price = settings.get('FEE_PRICE')
     92     if price == None:
     93         fee_oracle = settings.get('FEE_ORACLE')
     94         # TODO: pass on code and input
     95         r = fee_oracle.get_fee()
     96         price = r[0]
     97 
     98     value = settings.get('VALUE')
     99     if config.true('_TOTAL'):
    100         delta = config.get('_FEE_LIMIT') * price
    101         value -= delta
    102         if value < 0:
    103             raise ValueError('Resulting value is negative')
    104         logg.info('total switch set, adjusting sent amount {} by {} to {}'.format(settings.get('VALUE'), delta, value))
    105 
    106     return value
    107 
    108 
    109 def process_settings_wallet(settings, config):
    110     wallet = chainlib.eth.cli.Wallet()
    111     wallet.from_config(config)
    112     
    113     settings.set('WALLET', wallet)
    114 
    115     try:
    116         if config.get('_NULL'):
    117             settings.set('RECIPIENT', None)
    118             return settings
    119     except KeyError:
    120         pass
    121 
    122     recipient_in = None
    123     try:
    124         recipient_in = config.get('_RECIPIENT')
    125     except KeyError:
    126         return settings
    127 
    128     if recipient_in == None:
    129         return settings
    130     elif recipient_in == 'null':
    131         settings.set('RECIPIENT', None)
    132         return settings
    133 
    134     if wallet.get_signer_address() == None and recipient_in != None:
    135         recipient_in = wallet.from_address(recipient_in)
    136         recipient_in = strip_0x(recipient_in)
    137 
    138     recipient = __try_zero_address(config, recipient_in)
    139 
    140     settings.set('RECIPIENT', recipient)
    141 
    142     return settings
    143 
    144 
    145 def process_settings_contract(settings, config):
    146     exec_address_in = None
    147     try:
    148         exec_address_in = config.get('_EXEC_ADDRESS')
    149     except KeyError:
    150         return settings
    151 
    152     if exec_address_in == None:
    153         return settings
    154 
    155     exec_address = to_checksum_address(exec_address_in)
    156     if not config.true('_UNSAFE') and exec_address != exec_address_in:
    157         raise ValueError('invalid checksum address: {}'.format(exec_address_in))
    158     exec_address = add_0x(exec_address)
    159 
    160     settings.set('EXEC', exec_address)
    161     return settings
    162 
    163 
    164 def process_settings_data(settings, config):
    165     data = None
    166     try:
    167         data = config.get('_DATA')
    168     except KeyError:
    169         settings.set('DATA', None)
    170         return settings
    171 
    172     if data == None:
    173         return settings
    174 
    175     settings.set('DATA', data)
    176     
    177     return settings
    178 
    179 
    180 def process_settings_value(settings, config):
    181     updated_value = __calculate_net_amount(settings, config)
    182     settings.set('VALUE', updated_value)
    183 
    184     return settings
    185 
    186 
    187 def process_settings_hash(settings, config):
    188     hshs = None
    189     try:
    190         hshs = config.get('_HASH')
    191     except KeyError:
    192         return settings
    193 
    194     if isinstance(hshs, str):
    195         hshs = [hshs]
    196 
    197     r = []
    198     for hsh in hshs:
    199         hsh = strip_0x(hsh)
    200         l = len(hsh)
    201         if l != 64:
    202             raise ValueError('invalid hash length {} for {}'.format(l, hsh))
    203         hsh = add_0x(hsh)
    204         r.append(hsh)
    205 
    206     settings.set('HASH', r)
    207     
    208     return settings
    209 
    210 
    211 def process_settings(settings, config):
    212     settings = base_process_settings(settings, config)
    213     settings = process_settings_wallet(settings, config)
    214     settings = process_settings_rpc(settings, config)
    215     settings = process_settings_blockspec(settings, config)
    216     settings = process_settings_data(settings, config)
    217     settings = process_settings_hash(settings, config)
    218     settings = process_settings_value(settings, config)
    219     settings = process_settings_contract(settings, config)
    220     return settings