Ejemplo n.º 1
0
class EthLocust(Locust):
    '''
    This is the abstract Locust class which should be subclassed.
    It provides an Ethereum JSON-RPC client that can be used for
    requests that will be tracked in Locust's statistics.
    '''
    def __init__(self, *args, **kwargs):
        super(EthLocust, self).__init__(*args, **kwargs)
        server, port = self.host.split(':')
        if int(port) == 443:
            tls_flag = True
        else:
            tls_flag = False
        self.client = EthJsonRpc(server, port, tls=tls_flag)
        self.addresses = self.get_target_address_list()

    def get_target_address_list(self, count=100):
        '''
        As part of the initialization, we build up a list of 1k addresses
        which will be the targets of the getBal call. We do it as part of the
        initialization so that we dont slow down the concurrent tests.
        '''
        addrs = []
        block = self.client.eth_getBlockByNumber()
        while len(addrs) < count:
            block = self.client.eth_getBlockByHash(block['parentHash'])
            if block['transactions'] is not None:
                addrs += [
                    t['to'] for t in block['transactions']
                    if t['to'] is not None
                ]
        # Use a set to dedupe commonly used addresses (coinbase, poloniex, etc)
        return list(set(addrs))
Ejemplo n.º 2
0
class EthLocust(Locust):
    '''
    This is the abstract Locust class which should be subclassed.
    It provides an Ethereum JSON-RPC client that can be used for
    requests that will be tracked in Locust's statistics.
    '''
    def __init__(self, *args, **kwargs):
        super(EthLocust, self).__init__(*args, **kwargs)
        server, port = self.host.split(':')
        if int(port) == 443:
            tls_flag = True
        else:
            tls_flag = False
        self.client = EthJsonRpc(server, port, tls=tls_flag)
        self.addresses = self.get_target_address_list()

    def get_target_address_list(self, count=100):
        '''
        As part of the initialization, we build up a list of 1k addresses
        which will be the targets of the getBal call. We do it as part of the
        initialization so that we dont slow down the concurrent tests.
        '''
        addrs = []
        block = self.client.eth_getBlockByNumber()
        while len(addrs) < count:
            block = self.client.eth_getBlockByHash(block['parentHash'])
            if block['transactions'] is not None:
                addrs += [
                    t['to']
                    for t in block['transactions']
                    if t['to'] is not None
                ]
        # Use a set to dedupe commonly used addresses (coinbase, poloniex, etc)
        return list(set(addrs))
Ejemplo n.º 3
0
class ContractWrapper:
    def __init__(
        self,
        the_code=False,
        the_sig=None,
        the_args=None,
        the_address=False,
        events_callback=False,
        deploy_callback=False,
        blocking_sleep_time=0.1,
        rpc_host=DEFAULT_RPC_HOST,
        rpc_port=DEFAULT_RPC_PORT,
        settings_confirm_states={},
        contract_address=False,
        start_at_current_block=False,
        auto_deploy=True,
        contract_thread_sleep_time=1.0,
        reorg_callback=False,
    ):
        """
        Simple contract wrapper, assists with deploying contract, sending transactions, and tracking event logs.
        
        Args:
        - the_code: solidity code for contract that should be deployed, prior to any operations.
        - the_address: address of already-deployed main contract.
        - contract_address: contract address, from previous `deploy()` call.
        - the_sig: optional constructor signature.
        - the_args: optional constructor args.
        - events_callback: callback for event messages e.g. `TheLog()`, `MintEvent()`, `LockupTokEvent()`, `TransferTokEvent()`.
        - deploy_callback: callback for contract deploys.
        - blocking_sleep_time: time to sleep when blocking and polling for a transaction receipt.
        """

        self.block_details = {}

        self.reorg_callback = reorg_callback
        self.confirmation_tracker = {
        }  ## {'block_hash':{'prev_block_hash':xx, 'block_num':yy}}

        self.done_block_nums = {}  ## {confirm_state:set()}
        self.done_transactions = {}  ## {confirm_state:set()}
        self.prev_block_num = {}  ## {confirm_state:set()}

        self.blocking_sleep_time = blocking_sleep_time

        self.c = EthJsonRpc(rpc_host, rpc_port)

        self.contract_thread_sleep_time = contract_thread_sleep_time

        self.start_at_current_block = start_at_current_block

        self.current_block_at_init = self.c.eth_blockNumber()

        if self.start_at_current_block:
            self.last_incoming_block = max(0, self.current_block_at_init - 1)
        else:
            self.last_incoming_block = 0

        self.starting_block_num = self.last_incoming_block

        self.msgs = {}  ## {block_num:[msg, msg, msg]}

        self.the_code = the_code
        self.the_sig = the_sig
        self.the_args = the_args

        self.contract_address = the_address

        assert self.the_code or self.contract_address

        self.loop_block_num = -1

        self.confirm_states = settings_confirm_states

        self.events_callback = events_callback

        self.pending_transactions = {}  ## {tx:callback}
        self.pending_logs = {}
        self.latest_block_num = -1

        self.latest_block_num_done = 0

        self.send_transaction_queue = Queue()

        self.is_deployed = False

        if auto_deploy:
            if the_address:
                assert self.check_anything_deployed(the_address), (
                    'NOTHING DEPLOYED AT SPECIFIED ADDRESS:', the_address)
                self.is_deployed = True
            elif the_code:
                self.deploy()

    def check_anything_deployed(self, address):
        """ Basic sanity check, checks if ANY code is deployed at provided address. """
        if self.c.eth_getCode(address) == '0x0':
            return False
        return True

    def deploy(
        self,
        the_sig=False,
        the_args=False,
        block=False,
        deploy_from=False,
        callback=False,
    ):
        """ Deploy contract. Optional args_sig and args used to pass arguments to contract constructor."""

        if the_sig is not False:
            self.the_sig = the_sig

        if the_args is not False:
            self.the_args = the_args

        assert self.the_code

        if deploy_from is False:
            deploy_from = self.c.eth_coinbase()

        print('DEPLOYING_CONTRACT...', 'deploy_from:', deploy_from, 'the_sig:',
              the_sig, 'the_args:', the_args)
        # get contract address
        xx = self.c.eth_compileSolidity(self.the_code)
        #print ('GOT',xx)
        compiled = get_compiled_code(xx)

        contract_tx = self.c.create_contract(
            from_=deploy_from,
            code=compiled,
            gas=3000000,
            sig=self.the_sig,
            args=self.the_args,
        )

        if block:
            ## NOTE: @yusef feel free to switch back to this method if you want:
            #print('CONTRACT DEPLOYED, WAITING FOR CONFIRMATION')
            #wait_for_confirmation(self.c, contract_tx)

            print('BLOCKING FOR RECEIPT..')
            while True:
                receipt = self.c.eth_getTransactionReceipt(
                    contract_tx)  ## blocks to ensure transaction is mined
                if receipt:
                    break
                sleep(self.blocking_sleep_time)
            print('GOT RECEIPT')
        else:
            self.pending_transactions[contract_tx] = (callback,
                                                      self.latest_block_num)

        self.contract_address = str(self.c.get_contract_address(contract_tx))
        self.is_deployed = True
        print('DEPLOYED', self.contract_address)
        return self.contract_address

    def loop_once(self):
        assert self.is_deployed, 'Must deploy contract first.'

        had_any_events = False

        if self.c.eth_syncing():
            print('BLOCKCHAIN_STILL_SYNCING')
            return False

        if self.events_callback is not False:
            had_any_events = self.poll_incoming()

        had_any_events = self.poll_outgoing() or had_any_events

        num_fails = 0

        while self.send_transaction_queue.qsize():
            print('TRY_TO_SEND')
            tries, args, kw = self.send_transaction_queue.get()
            try:
                self._send_transaction(*args, **kw)
            except Exception as e:
                print('FAILED_TO_SEND', e, tries, args, kw)
                sleep(1)  ## TODO
                self.send_transaction_queue.put((tries + 1, args, kw))
                break

        return had_any_events

    def check_for_reorg(
        self,
        block_num,
    ):
        """ Check for reorg since last check, and reorgs during our reorg rewinding... """
        print('START check_for_reorg', block_num)

        return
        block_num = ethereum.utils.parse_int_or_hex(block_num)

        while True:

            cur_num = block_num
            had_reorg = False

            while True:
                if cur_num == self.starting_block_num:
                    break

                assert cur_num >= self.starting_block_num, (
                    cur_num, self.starting_block_num)

                ## Get info for prev and current:

                for x_block_num in [block_num, block_num - 1]:
                    if x_block_num not in self.block_details:
                        rh = self.c.eth_getBlockByNumber(x_block_num)

                        ## Strip down to just a couple fields:
                        block_h = {
                            'timestamp':
                            ethereum.utils.parse_int_or_hex(rh['timestamp']),
                            'hash':
                            rh['hash'],
                            'parentHash':
                            rh['parentHash'],
                            'blockNumber':
                            x_block_num,
                        }
                        self.block_details[x_block_num] = block_h

                ## Check for reorg:

                block_h = self.block_details[block_num]

                if block_h['parentHash'] != self.block_details[
                        block_h['blockNumber'] - 1]['hash']:
                    print('!!! REORG', block_num, '->', cur_num)
                    cur_num -= 1
                    self.latest_done_block = cur_num
                    had_reorg = True
                    continue
                break

            ## Rewind state if had_reorg:

            if had_reorg and (self.reorg_callback is not False):
                self.reorg_callback(cur_num)
                self.last_incoming_block = cur_num - 1

            ## If had_reorg, loop again - to detect another reorg that occured while we tracked down the reorg...

            if not had_reorg:
                break

        return had_reorg

    def poll_incoming(self, chunk_size=50):
        """
        https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter

        - track buffer of events from old blocks
        - track pointer to last processed block
        """

        assert self.is_deployed, 'Must deploy contract first.'

        #self.latest_block_num = self.c.eth_blockNumber()

        from_block = self.last_incoming_block + 1

        params = {
            'from_block': fixed_int_to_hex(from_block),
            'to_block': 'latest',  #fixed_int_to_hex(from_block + chunk_size),
            'address': self.contract_address,
        }

        print('eth_newFilter', 'from_block:', from_block, 'params:', params)

        self.the_filter = str(self.c.eth_newFilter(**params))

        num_blocks = len(self.msgs)

        xx_msgs = self.c.eth_getFilterLogs(self.the_filter)

        for msg in xx_msgs:
            msg['blockNumber'] = ethereum.utils.parse_int_or_hex(
                msg['blockNumber'])
            if msg['blockNumber'] not in self.msgs:
                self.msgs[msg['blockNumber']] = []
            self.msgs[msg['blockNumber']].append(msg)

        if num_blocks == len(self.msgs):
            ## Nothing new
            assert not len(xx_msgs), len(xx_msgs)
            return False

        for do_state, state_num_blocks in self.confirm_states.items():

            longest_confirm_state = max(self.confirm_states.values())
            newest_block_num = max(max(self.msgs), self.last_incoming_block)

            ## Oldest to newest:

            for nn in xrange(
                    max(1, self.last_incoming_block - state_num_blocks),
                    newest_block_num + 1,
            ):

                if self.check_for_reorg(nn):
                    ## Just wait for next call to poll_incoming() before resuming.
                    return False

                if nn in self.msgs:
                    for msg in self.msgs[nn]:
                        print('EMIT', do_state, nn, msg['data'])
                        self.events_callback(msg=msg,
                                             receipt=False,
                                             received_via=do_state)

            ## Clear out old buffer:

            for nn in self.msgs.keys():
                if nn < newest_block_num - longest_confirm_state - 1:
                    del self.msgs[nn]

        self.last_incoming_block = newest_block_num

        return True

        if False:
            ## START CHECKS

            if do_state not in self.done_transactions:
                self.done_transactions[do_state] = set()
                self.done_block_nums[do_state] = set()

            msg_block_num = ethereum.utils.parse_int_or_hex(msg['blockNumber'])

            if cm == 0:
                assert msg_block_num not in self.done_block_nums[do_state], (
                    'Seen block twice?',
                    msg_block_num,
                )
                self.done_block_nums[do_state].add(msg_block_num)

            if do_state in self.prev_block_num:
                assert msg_block_num >= self.prev_block_num[do_state], (
                    'REORG?',
                    msg_block_num,
                    self.prev_block_num[do_state],
                )
            self.prev_block_num[do_state] = msg_block_num

            assert msg['transactionHash'] not in self.done_transactions[
                do_state], (
                    'Seen transaction twice?',
                    msg_block_num,
                    msg['transactionHash'],
                )
            self.done_transactions[do_state].add(msg['transactionHash'])

            ## END CHECKS

        return had_any_events

    def _start_contract_thread(
        self,
        terminate_on_exception=False,
    ):
        while True:
            try:
                had_any_events = self.loop_once()
            except Exception as e:
                print('-----LOOP_ONCE_EXCEPTION', e)
                #exit(-1)
                raise

                if terminate_on_exception:
                    raise
                continue

            if not had_any_events:
                print('NO_NEW_EVENTS')

            sleep(self.contract_thread_sleep_time)

    def start_contract_thread(
        self,
        start_in_foreground=False,
        terminate_on_exception=False,
    ):
        """
        Start ContractWrapper loop_once() in background thread, which (in that thread!) calls back to self.process_event()
        """
        if start_in_foreground:
            self._start_contract_thread(
                terminate_on_exception=terminate_on_exception)
        else:
            self.t = Thread(
                target=self._start_contract_thread,
                args=(terminate_on_exception, ),
            )
            self.t.daemon = True
            self.t.start()

    def send_transaction(self, *args, **kw):
        assert len(args) <= 2
        if kw.get('block'):
            self.send_transaction(*args, **kw)
        else:
            self.send_transaction_queue.put((0, args, kw))

    def _send_transaction(
        self,
        args_sig,
        args,
        callback=False,
        send_from=False,
        block=False,
        gas_limit=False,
        gas_price=100,
        value=100000000000,
    ):
        """
        1) Attempt to send transaction.
        2) Get first confirmation via transaction receipt.
        3) Re-check receipt again after N blocks pass.
        
        https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction
        """

        assert self.is_deployed, 'Must deploy contract first.'

        print('SEND_TRANSACTION:', args_sig, args)

        if send_from is False:
            send_from = self.c.eth_coinbase()

        send_to = self.contract_address

        print('====TRANSACTION')
        print('send_from', send_from)
        print('send_to', send_to)
        print('args_sig', args_sig)
        print('args', args)
        #print ('gas', gas_limit)

        gas_limit = 1000000
        gas_price = self.c.DEFAULT_GAS_PRICE
        value = web3.utils.currency.to_wei(1, 'ether')

        data = self.c._encode_function(args_sig, args)
        data_hex = '0x' + data.encode('hex')

        tx = self.c.eth_sendTransaction(
            from_address=send_from,
            to_address=send_to,
            data=data_hex,
            gas=gas_limit,
            gas_price=gas_price,
            value=value,
        )

        if block:
            print('BLOCKING FOR RECEIPT..')
            while True:
                receipt = self.c.eth_getTransactionReceipt(
                    tx)  ## blocks to ensure transaction is mined
                if receipt:
                    break
                sleep(self.blocking_sleep_time)
            print('GOT RECEIPT')
            #print ('GOT_RECEIPT', receipt)
            #if receipt['blockNumber']:
            #    self.latest_block_num = max(ethereum.utils.parse_int_or_hex(receipt['blockNumber']), self.latest_block_num)
        else:
            self.pending_transactions[tx] = (callback, self.latest_block_num)

        self.latest_block_num = self.c.eth_blockNumber()

        return tx

    def poll_outgoing(self):
        """
        Confirm outgoing transactions.
        """

        assert self.is_deployed, 'Must deploy contract first.'

        had_any_events = False
        if self.pending_transactions:
            had_any_events = True

        for tx, (callback,
                 attempt_block_num) in self.pending_transactions.items():

            ## Compare against the block_number where it attempted to be included:

            if (attempt_block_num <= self.latest_block_num -
                    self.confirm_states['BLOCKCHAIN_CONFIRMED']):
                continue

            receipt = self.c.eth_getTransactionReceipt(tx)

            if receipt is not None and 'blockNumber' in receipt:
                actual_block_number = ethereum.utils.parse_int_or_hex(
                    receipt['blockNumber'])
            else:
                ## TODO: wasn't confirmed after a long time.
                actual_block_number = False

            ## Now compare against the block_number where it was actually included:

            if (actual_block_number is not False) and (
                    actual_block_number >= self.latest_block_num -
                    self.confirm_states['BLOCKCHAIN_CONFIRMED']):
                if callback is not False:
                    callback(receipt)
                del self.pending_transactions[tx]

        return had_any_events

    def read_transaction(self, args_sig, value):
        rr = self.c.call(self.c.eth_coinbase(), self.contract_address,
                         args_sig, value)
        return rr

    def sign(self, user_address, value):
        rr = self.c.eth_sign(self.c.eth_coinbase(), self.contract_address,
                             user_address, value)
        return rr
Ejemplo n.º 4
0
db_name = 'db_name'
k = 'my_key'
v = '0xabcdef'
print(c.db_putHex(db_name, k, v))
x = c.db_getHex(db_name, k)
print(x)
assert v == x

################################################################################
print('*' * 80)

b = (199583, '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f')
print(c.eth_getBlockByHash(b[1], tx_objects=False))

for x in ['earliest', 'latest', 'pending', b[0]]:
    print(c.eth_getBlockByNumber(x, tx_objects=False))

tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3'
print(c.eth_getTransactionByHash(tx))

################################################################################
print('*' * 80)

code = 'contract Test {}'
print(c.eth_compileSolidity(code))

################################################################################
print('*' * 80)

b = (246236, '0xcd43703a1ead33ffa1f317636c7b67453c5cc03a3350cd71dbbdd70fcbe0987a')
index = 2
def main():
    #
    # receive contract addr
    #
    if len(sys.argv) != 3:
        print('Usage:\npython user.py <contract addr> <account addr>')
        sys.exit(-1)
    contract_addr = sys.argv[1]
    account_addr = sys.argv[2]

    #
    # create rpc interface
    #
    try:
        print('-' * 80)
        rpc = EthJsonRpc(RPC_HOST, RPC_PORT)
        print('client software: {}'.format(rpc.web3_clientVersion()))
        print('block: {}'.format(rpc.eth_blockNumber()))
        print('address: {}'.format(rpc.eth_coinbase()))
    except:
        print('unable to connect to rpc server at {}:{}'.format(
            RPC_HOST, RPC_PORT))
        sys.exit(-1)

    #
    # check contract is online
    #
    print('-' * 80)
    if rpc.eth_getCode(contract_addr) == '0x0':
        print('!!! contract code not available on blockchain !!!')
        sys.exit(-1)
    print('found contract on blockchain!')

    #
    # console
    #
    topics = []
    print('-' * 80)
    print('starting chat command line...')
    while True:
        #
        # simply read input
        #
        sys.stdout.write('>> ')
        command = sys.stdin.readline()

        #
        # quit?
        #
        if 'q' in command:
            sys.exit(0)

        #
        # show help
        #
        elif command == '\n' or 'help' in command:
            print('commands: help, send, status, topics, search, listen')

        #
        # compose new message
        #
        elif 'send' in command:
            print('-' * 80)
            print('[composing new message]')
            sys.stdout.write('message....: ')
            msg = sys.stdin.readline().strip()
            sys.stdout.write('image file.: ')
            img = sys.stdin.readline().strip()
            sys.stdout.write('custom tags: ')
            tag = sys.stdin.readline().strip()
            print('-' * 80)
            print('sending...')
            # loading image
            try:
                image = Image.open(img)
            except Exception as e:
                print('loading {} failed'.format(img))
                continue
            # prediction
            print('precessing image...')
            label = ImageClassifier.predict(img)
            if label is None:
                print('classification failed')
                continue
            print('label: {}'.format(label))
            tag += ' #' + label
            bs = ImageHelper.imgToBytes(image)
            tx = rpc.call_with_transaction(
                account_addr,
                contract_addr,
                'setNewUserState(string,bytes,string)', [msg, bs, tag],
                gas=GAS)
            print('done, transaction id: {}'.format(tx))

        #
        # get own last post
        #
        elif 'status' in command:
            print('-' * 80)
            print('[receiving last post]')
            userMessage, userImage, userTags = rpc.call(
                contract_addr, 'getUserState(address)', [account_addr],
                ['string', 'bytes', 'string'])
            if not userMessage:
                print('nothing posted yet')
                continue
            print('  content: {}'.format(userMessage))
            print('  tags...: {}'.format(userTags))
            ImageHelper.bytesToImg(userImage).show()

        #
        # set tag filters
        #
        elif 'topics' in command:
            topics = [t.strip() for t in command.split()[1:]]
            if len(topics) == 0:
                print('please provide actual topics after <topics> command')
                continue
            print('filter set for messages on topics: {}'.format(topics))

        #
        # search complete blockchain for messages with certain tags
        #
        elif 'search' in command:
            if len(topics) == 0:
                print('call topics first')
                continue
            curBlock = rpc.eth_blockNumber()
            for i in range(curBlock + 1):
                for trans in rpc.eth_getBlockByNumber(i)['transactions']:
                    res = Decoder.decodeABI(trans['input'])
                    if res is None:
                        continue
                    msg, code, tags = res
                    if all(t not in tags for t in topics):
                        continue
                    print('-' * 80)
                    print('message from user {} (block {}):'.format(
                        trans['from'], i))
                    print('  content: {}'.format(msg))
                    print('  tags...: {}'.format(tags))
                    ImageHelper.bytesToImg(code).show(title='{}'.format(tags))

        #
        # start listening for messages
        #
        elif 'listen' in command:
            if len(topics) == 0:
                print('call topics first')
                continue
            global LISTENING
            LISTENING = True
            curBlock = rpc.eth_blockNumber()
            while LISTENING:
                newBlock = rpc.eth_blockNumber()
                if newBlock > curBlock:
                    print('new block detected ({})'.format(newBlock))
                    curBlock = newBlock
                    for trans in rpc.eth_getBlockByNumber(
                            newBlock)['transactions']:
                        res = Decoder.decodeABI(trans['input'])
                        if res is None:
                            continue
                        msg, code, tags = res
                        if all(t not in tags for t in topics):
                            continue
                        print('-' * 80)
                        print('message from user {} (block {}):'.format(
                            trans['from'], newBlock))
                        print('  content: {}'.format(msg))
                        print('  tags...: {}'.format(tags))
                        ImageHelper.bytesToImg(code).show(
                            title='{}'.format(tags))
                time.sleep(1)

        #
        # default response
        #
        else:
            print('command not recognized')
Ejemplo n.º 6
0
class EthereumBlockchain:
    def __init__(self,
                 the_code = False,
                 the_sig = None,
                 the_args = None,
                 the_address = False,
                 rpc_host = DEFAULT_RPC_HOST,
                 rpc_port = DEFAULT_RPC_PORT,
                 background_thread_sleep_time = 1.0,
                 ):
        
        self.con = EthJsonRpc(rpc_host, rpc_port)
        
        self.the_code = the_code
        self.the_sig = the_sig
        self.the_args = the_args
        
        self.contract_address = the_address
        
        assert self.the_code or self.contract_address
        
        self.loop_once_started = False
        
        self.sig_to_topic_id_cache = {}
        
        self.send_transaction_queue = Queue()
        
        self.background_thread_sleep_time = background_thread_sleep_time

        self.pending_transactions = {}  ## {tx:callback}
        
        self.is_deployed = False
        
        if the_address:
            assert self.check_anything_deployed(the_address), ('NOTHING DEPLOYED AT SPECIFIED ADDRESS:', the_address)
            self.is_deployed = True
        elif the_code:
            if auto_deploy:
                self.deploy()

        
    #def setup_create_pending_transaction(func):
    #    self._create_pending_transaction = func
    
    #def setup_logic_callback(func):
    #    self._logic_callback = func
    
    def event_sig_to_topic_id(self, sig):
        """ Compute ethereum topic_ids from function signatures. """
        if sig in self.sig_to_topic_id_cache:
            return self.sig_to_topic_id_cache[sig]
        name = sig[:sig.find('(')]
        types = [x.strip().split()[0] for x in sig[sig.find('(')+1:sig.find(')')].split(',')]
        topic_id = ethereum.utils.int_to_hex(ethereum.abi.event_id(name,types))
        self.sig_to_topic_id_cache[sig] = topic_id
        return topic_id

    def setup_event_callbacks(self,
                              log_handlers,
                              pending_handlers,
                              ):
        self.log_handlers = log_handlers
        self.log_handlers_hashed = {((x == 'DEFAULT') and 'DEFAULT' or self.event_sig_to_topic_id(x)):y
                                    for x,y
                                    in log_handlers.items()}
        self.pending_handlers = pending_handlers
    
    def logic_callback(self, msg, *args, **kw):
        default_func = self.log_handlers_hashed.get('DEFAULT', False)
        
        if 'topics' not in msg:
            assert default_func is not False, ('Unknown topic_id and no DEFAULT handler.')
            print ('PROXY logic_callback()', '->', default_func, kw)
            default_func(msg, *args, **kw)
            return
        
        for topic in msg['topics']:
            func = self.log_handlers_hashed.get(topic, default_func)
            print ('PROXY logic_callback()', topic, '->', func)
            assert func is not False, ('Unknown topic_id and no DEFAULT handler.', topic, kw)
            func(msg, *args, **kw)
    
    def simulate_pending(self,
                         args_sig,
                         args,
                         *aa, **bb):
        """ 
        See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#events 
        """
        ## TODO: support indexed topics?
        
        func = self.pending_handlers.get(args_sig, self.pending_handlers.get('DEFAULT', False))
        
        print ('Proxy: simulate_pending()', args_sig, '->', func)
        
        return func(args_sig, args, *aa, **bb)

    def get_block_by_hash_callback(self, block_hash):
        """
        Get block by blockHash.
        
        https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash
        """
        print ('bcc.get_block_by_hash_callback()', block_hash)

        rh = self.con.eth_getBlockByHash(block_hash)
        
        for k in ['number', 'timestamp']:
            rh[k] = ethereum.utils.parse_int_or_hex(rh[k])
        
        return rh
        
    
    def get_logs_by_block_num_callback(self, block_num):
        """
        Get event logs for a particular block num. It's OK if the block_num has an unexpected hash, 
        that'll be taken care of by caller.
        
        https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
        """
        print ('bcc.get_logs_by_block_num_callback()', block_num)
        
        the_filter = self.con.eth_newFilter(from_block =  fixed_int_to_hex(block_num),
                                            to_block = fixed_int_to_hex(block_num),
                                            address = self.contract_address,
                                            )
        
        rr =  self.con.eth_getFilterLogs(str(the_filter))

        rr2 = []
        for msg in rr:
            #assert 'topics' in msg, list(sorted(msg.keys()))
            got_num = ethereum.utils.parse_int_or_hex(msg['blockNumber'])
            if got_num != block_num:
                continue
            msg['data'] = solidity_string_decode(msg['data'])
            msg['blockNumber'] = got_num
            msg["logIndex"] = ethereum.utils.parse_int_or_hex(msg['logIndex'])
            msg["transactionIndex"] = ethereum.utils.parse_int_or_hex(msg['transactionIndex'])
            #msg_data = loads_compact(msg['data'])
            #payload_decoded = loads_compact(msg_data['payload'])
            rr2.append(msg)
        rr = rr2
        
        return rr

    def get_latest_block_number(self):
        print ('bcc.get_latest_block_number()')
        bn = self.con.eth_blockNumber()
        return bn
    
    def get_latest_block_callback(self):
        """
        Returns the single latest block. Missing intermediate blocks will be automatically looked up by caller.
        """
        print ('bcc.get_latest_block_callback()')
        bn = self.get_latest_block_number()
        block = self.con.eth_getBlockByNumber(bn)
        return block

                
    def check_anything_deployed(self, address):
        """ Basic sanity check, checks if ANY code is deployed at provided address. """
        print ('bcc.check_anything_deployed()', address)
        if self.con.eth_getCode(address) == '0x0':
            return False
        return True
            
    def deploy(self,
               the_sig = False,
               the_args = False,
               block = False,
               deploy_from = False,
               callback = False,
               ):
        """ Deploy contract. Optional args_sig and args used to pass arguments to contract constructor."""
        print ('bcc.deploy()')

        if the_sig is not False:
            self.contract_sig = the_sig
        
        if the_args is not False:
            self.contract_args = the_args

        assert self.the_code

        if deploy_from is False:
            deploy_from = self.con.eth_coinbase()
        
        print ('DEPLOYING_CONTRACT...', 'deploy_from:', deploy_from, 'the_sig:', the_sig, 'the_args:', the_args)        
        # get contract address
        xx = self.con.eth_compileSolidity(self.the_code)
        #print ('GOT',xx)
        
        compiled = None
        
        try:
            compiled = xx['code']
        except KeyError:
            # geth seems to like putting the compiler output into an inner dict keyed by input filename,
            # e.g {'CCCoinToken.sol': {'code': '...', 'etc': '...'}
            for k, v in xx.iteritems():
                if isinstance(v, dict) and 'code' in v:
                    compiled = v['code']
                    break
        
        assert compiled
        
        contract_tx = self.con.create_contract(from_ = deploy_from,
                                               code = compiled,
                                               gas = 3000000,
                                               sig = self.contract_sig,
                                               args = self.contract_args,
                                               )

        if block:
            ## NOTE: @yusef feel free to switch back to this method if you want:
            #print('CONTRACT DEPLOYED, WAITING FOR CONFIRMATION')
            #wait_for_confirmation(self.c, contract_tx)
            
            print ('BLOCKING FOR RECEIPT..')
            while True:
                receipt = self.con.eth_getTransactionReceipt(contract_tx) ## blocks to ensure transaction is mined
                if receipt:
                    break
                sleep(self.blocking_sleep_time)
            print ('GOT RECEIPT')
        else:
            self.pending_transactions[contract_tx] = callback
        
        self.contract_address = str(self.con.get_contract_address(contract_tx))
        self.is_deployed = True
        print ('DEPLOYED', self.contract_address)
        return self.contract_address

    def send_transaction(self, *args, **kw):
        """
        1) If possible create simulated outputs of transactions, to use as pending state.
        2) Queue the transaction for blockchain commit.
        
        Used for e.g.:
        - addLog(bytes)
        - mintTokens(address, uint, uint, uint, uint, uint, uint)
        - withdrawTok(bytes)
        - lockupTok(bytes)
        """
        print ('bcc.send_transaction()')

        assert len(args) <= 2
        #assert self.loop_once_started, 'loop_once() not started?'

        ## Potentially slow blocking call to commit it to the blockchain:

        if kw.get('block'):
            ## Send transaction in blocking mode, and grab actual event logs that are committed:

            rh = self.inner_send_transaction(*args, **kw)
            pending_logs = rh['pending_logs']
            is_pending = False
            
        else:
            ## Run callbacks, return simulated event logs where possible:

            self.send_transaction_queue.put((0, args, kw))
            pending_logs = self.simulate_pending(*args, **kw)
            is_pending = True
        
        ## Run logic_callback() against pending transactions:
        
        for log in pending_logs:
            print ('CALLING', 'is_pending:', is_pending, 'is_noop:', log.get('is_noop', False))
                                
            self.logic_callback(log,
                                is_pending = is_pending,
                                is_noop = log.get('is_noop', False)
                                )

        return pending_logs
            
    def inner_send_transaction(self,
                               args_sig,
                               args,
                               callback = False,
                               send_from = False,
                               block = False,
                               gas_limit = False,
                               gas_price = 100,
                               value = 100000000000,
                               ):
        """
        1) Attempt to send transaction.
        2) Get first confirmation via transaction receipt.
        3) Re-check receipt again after N blocks pass.
        
        https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction
        """
        print ('bcc.inner_send_transaction()')

        assert self.is_deployed, 'Must deploy contract first.'

        print ('SEND_TRANSACTION:', args_sig, args)

        if send_from is False:
            send_from = self.con.eth_coinbase()
        
        send_to = self.contract_address 

        print ('====TRANSACTION')
        print ('send_from', send_from)
        print ('send_to', send_to)
        print ('args_sig', args_sig)
        print ('args', args)
        #print ('gas', gas_limit)
        
        gas_limit = 1000000
        gas_price = self.con.DEFAULT_GAS_PRICE
        value = web3.utils.currency.to_wei(1,'ether')

        data = self.con._encode_function(args_sig, args)
        data_hex = '0x' + data.encode('hex')
        
        tx = self.con.eth_sendTransaction(from_address = send_from,
                                          to_address = send_to,
                                          data = data_hex,
                                          gas = gas_limit,
                                          gas_price = gas_price,
                                          value = value,
                                          )
        
        if block:
            print ('BLOCKING FOR RECEIPT..')
            while True:
                receipt = self.con.eth_getTransactionReceipt(tx) ## blocks to ensure transaction is mined
                if receipt:
                    break
                sleep(self.blocking_sleep_time)
            print ('GOT RECEIPT')
            #print ('GOT_RECEIPT', receipt)
            #if receipt['blockNumber']:
            #    self.latest_block_num = max(ethereum.utils.parse_int_or_hex(receipt['blockNumber']), self.latest_block_num)
        else:
            self.pending_transactions[tx] = callback
        
        #self.latest_block_num = self.con.eth_blockNumber()
        
        return {'tx':tx}

    def poll_outgoing_receipts(self):
        """
        Check for transaction receipts on transactions sent from this node.
        TODO - why not replace this with just watching for incoming transactions???
        """
        
        assert self.is_deployed, 'Must deploy contract first.'

        had_any_events = False
        if self.pending_transactions:
            had_any_events = True
        
        for tx, callback in self.pending_transactions.items():
            
            receipt = self.con.eth_getTransactionReceipt(tx)
            
            if receipt is not None and 'blockNumber' in receipt:
                actual_block_number = ethereum.utils.parse_int_or_hex(receipt['blockNumber'])
            else:
                ## TODO: wasn't confirmed after a long time.
                actual_block_number = False
            
            ## Now compare against the block_number where it was actually included:
            
            if actual_block_number is not False:
                if callback is not False:
                    callback(receipt)
                del self.pending_transactions[tx]
        
        return had_any_events
    
    
    def _start_background_thread(self,
                                 terminate_on_exception = False,
                                 ):
        last_event = False
        
        while True:
            try:
                had_any_events = self.loop_once_blockchain()
            except Exception as e:
                print ('-----LOOP_ONCE_EXCEPTION', e)
                #exit(-1)
                raise
                
                if terminate_on_exception:
                    raise
                continue
            
            if had_any_events:
                last_event = time()
            else:
                print ('NO_NEW_EVENTS', last_event and (time() - last_event))
            
            sleep(self.background_thread_sleep_time)
    
    def start_background_thread(self,
                                start_in_foreground = False,
                                terminate_on_exception = False,
                                ):
        """
        Start ContractWrapper loop_once() in background thread, which (in that thread!) calls back to self.process_event()
        """
        if start_in_foreground:
            self._start_background_thread(terminate_on_exception = terminate_on_exception)
        else:
            self.t = Thread(target = self._start_background_thread,
                            args = (terminate_on_exception,),
                            )
            self.t.daemon = True
            self.t.start()
    
            

    def loop_once_blockchain(self):
        ## Check for available write receipts:
        #self.poll_outgoing_receipts()

        self.loop_once_started = True
        
        ## Do write transactions transactions:
        
        while self.send_transaction_queue.qsize():
            print ('TRY_TO_SEND')
            tries, args, kw = self.send_transaction_queue.get()
            try:
                self.inner_send_transaction(*args, **kw)
            except Exception as e:
                print ('FAILED_TO_SEND', e, tries, args, kw)
                sleep(1) ## TODO
                self.send_transaction_queue.put((tries + 1, args, kw))
                break
Ejemplo n.º 7
0
from ethjsonrpc import EthJsonRpc  # to use Parity-specific methods, import ParityEthJsonRpc
import binascii

c = EthJsonRpc("something.420blaze.in", 8545)
print c.net_version()

chars = [""] * 256
for i in range(500):
    tx = c.eth_getBlockByNumber(i, True)

    if len(tx['transactions']) > 1:
        inp = binascii.unhexlify(tx['transactions'][0]['input'][2:])
        if 'character' in inp:
            index = ord(
                inp.split(
                    "\xd1\xd1>\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
                )[1][0])

            char = inp.split("character: ")[1][0]
            print index, char
            chars[index] = char

print "".join(chars)
Ejemplo n.º 8
0
db_name = 'db_name'
k = 'my_key'
v = '0xabcdef'
print c.db_putHex(db_name, k, v)
x = c.db_getHex(db_name, k)
print x
assert v == x

################################################################################
print '*' * 80

b = (199583, '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f')
print c.eth_getBlockByHash(b[1], tx_objects=False)

for x in ['earliest', 'latest', 'pending', b[0]]:
    print c.eth_getBlockByNumber(x, tx_objects=False)

tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3'
print c.eth_getTransactionByHash(tx)

################################################################################
print '*' * 80

code = 'contract Test {}'
print c.eth_compileSolidity(code)

#code = ''
#print c.eth_compileSerpent(code)

#code = ''
#print c.eth_compileLLL(code)
Ejemplo n.º 9
0
# k = 'my_key'
# v = '0xabcdef'
# print(geth_client.db_putHex(db_name, k, v))
# x = geth_client.db_getHex(db_name, k)
# print(x)
# assert v == x

################################################################################
print('*' * 80)

b = (199583,
     '0x19d761c6f944eefe91ad70b9aff3d2d76c972e5bb68c443eea7c0eaa144cef9f')
print(geth_client.eth_getBlockByHash(b[1], tx_objects=False))

for x in ['earliest', 'latest', 'pending', b[0]]:
    print(geth_client.eth_getBlockByNumber(x, tx_objects=False))

tx = '0x12cd5d9a82049154c8990214a551479853d1bfe45852688833bc4ef86a29b1a3'
print(geth_client.eth_getTransactionByHash(tx))

################################################################################
print('*' * 80)

code = 'contract Test {}'
print(geth_client.eth_compileSolidity(code))

#code = ''
#print(geth_client.eth_compileSerpent(code)

#code = ''
#print(geth_client.eth_compileLLL(code)