contract-registry

Ethereum Smart Contract key-value registry
Info | Log | Files | Refs

registry.py (3577B)


      1 # standard imports
      2 import os
      3 import logging
      4 import json
      5 import hashlib
      6 
      7 # third-party imports
      8 from chainlib.eth.contract import (
      9         ABIContractEncoder,
     10         ABIContractType,
     11         abi_decode_single,
     12         )
     13 from chainlib.chain import ChainSpec
     14 from chainlib.eth.constant import (
     15         ZERO_ADDRESS,
     16         )
     17 from chainlib.jsonrpc import JSONRPCRequest
     18 from hexathon import (
     19         even,
     20         add_0x,
     21         )
     22 from chainlib.eth.tx import TxFactory
     23 
     24 # local imports
     25 from .encoding import (
     26         to_identifier,
     27         from_identifier_hex,
     28         )
     29 from .interface import Registry
     30 
     31 logg = logging.getLogger(__name__)
     32 
     33 moddir = os.path.dirname(__file__)
     34 datadir = os.path.join(moddir, 'data')
     35 
     36 
     37 class ContractRegistry(Registry):
     38 
     39     default_chain_spec = None
     40     __chains_registry = {}
     41 
     42     __abi = None
     43     __bytecode = None
     44 
     45     @staticmethod
     46     def abi():
     47         if ContractRegistry.__abi == None:
     48             f = open(os.path.join(datadir, 'Registry.json'), 'r')
     49             ContractRegistry.__abi = json.load(f)
     50             f.close()
     51         return ContractRegistry.__abi
     52 
     53 
     54     @staticmethod
     55     def bytecode():
     56         if ContractRegistry.__bytecode == None:
     57             f = open(os.path.join(datadir, 'Registry.bin'))
     58             ContractRegistry.__bytecode = f.read()
     59             f.close()
     60         return ContractRegistry.__bytecode
     61 
     62 
     63     @staticmethod
     64     def gas(code=None):
     65         return 1500000
     66 
     67 
     68     def constructor(self, sender_address, identifier_strings=[]):
     69         # TODO: handle arrays in chainlib encode instead
     70         enc = ABIContractEncoder()
     71         enc.uint256(32)
     72         enc.uint256(len(identifier_strings))
     73         for s in identifier_strings:
     74             enc.bytes32(to_identifier(s))
     75         data = enc.get_contents()
     76 
     77         tx = self.template(sender_address, None, use_nonce=True)
     78         tx = self.set_code(tx, ContractRegistry.bytecode() + data)
     79         logg.debug('bytecode {}\ndata {}\ntx {}'.format(ContractRegistry.bytecode(), data, tx))
     80         return self.build(tx)
     81 
     82 
     83     @staticmethod
     84     def address(address=None):
     85         if address != None:
     86             ContractRegistry.__address = address
     87         return Registry.__address
     88         
     89 
     90     @staticmethod
     91     def load_for(chain_spec):
     92         chain_str = str(chain_spec)
     93         raise NotImplementedError()
     94 
     95 
     96     def set(self, contract_address, sender_address, identifier_string, address):
     97         if len(identifier_string) > 32:
     98             raise ValueError('String too long')
     99         enc = ABIContractEncoder()
    100         enc.method('set')
    101         enc.typ(ABIContractType.BYTES32)
    102         enc.typ(ABIContractType.ADDRESS)
    103         identifier = to_identifier(identifier_string)
    104         enc.bytes32(identifier)
    105         enc.address(address)
    106         data = enc.encode()
    107         tx = self.template(sender_address, contract_address, use_nonce=True)
    108         tx = self.set_code(tx, data)
    109         return self.build(tx)
    110 
    111 
    112     def identifier(self, contract_address, idx, sender_address=ZERO_ADDRESS, id_generator=None):
    113         j = JSONRPCRequest(id_generator)
    114         o = j.template()
    115         o['method'] = 'eth_call'
    116         enc = ABIContractEncoder()
    117         enc.method('identifiers')
    118         enc.typ(ABIContractType.UINT256)
    119         enc.uint256(idx)
    120         data = add_0x(enc.encode())
    121         tx = self.template(sender_address, contract_address)
    122         tx = self.set_code(tx, data)
    123         o['params'].append(self.normalize(tx))
    124         o = j.finalize(o)
    125         return o
    126 
    127 
    128     @classmethod
    129     def parse_identifier(self, v):
    130         return from_identifier_hex(v)