示例#1
0
class Oracle:
    def __init__(self):
        self.communication = OracleCommunication()
        self.db = OracleDb()
        self.btc = BitcoinClient()
        self.kv = KeyValue(self.db)

        self.task_queue = TaskQueue(self.db)

        self.handlers = op_handlers
        self.signer = TransactionSigner(self)

    def handle_request(self, request):
        logging.debug(request)
        operation, message = request

        if not operation in self.handlers:
            logging.debug("operation {} not supported".format(operation))
            return

        handler = self.handlers[operation]

        try:
            message.message = json.loads(message.message)
            if 'message_id' in message.message:
                logging.info('parsing message_id: %r' %
                             message.message['message_id'])
            handler(self).handle_request(message)
        except:
            logging.debug(message)
            logging.exception('error handling the request')

        # Save object to database for future reference
        db_class = self.db.operations[operation]
        if db_class:
            db_class(self.db).save(message)

    def handle_task(self, task):
        operation = task['operation']
        assert (operation in self.handlers)
        handler = self.handlers[operation]
        handler(self).handle_task(task)

        operation = task['operation']
        handler = self.handlers[operation]
        if handler:
            if handler(self).valid_task(task):
                return task
            else:
                logging.debug('Task marked as invalid by handler')
                self.task_queue.done(task)
                return None
        else:
            logging.debug("Task has invalid operation")
            self.task_queue.done(task)
            return None

    def is_fee_sufficient(self, addr, fee):
        if addr != self.oracle_address:
            return False
        if fee < Decimal(ORACLE_FEE):
            return False
        return True

    def run(self):

        if not ORACLE_ADDRESS:
            self.oracle_address = self.kv.get_by_section_key(
                'config', 'ORACLE_ADDRESS')

            if self.oracle_address is None:
                new_addr = self.btc.server.getnewaddress()
                self.oracle_address = new_addr
                logging.error("created a new address: '%s'" % new_addr)
                self.kv.store('config', 'ORACLE_ADDRESS', new_addr)
        else:
            self.oracle_address = ORACLE_ADDRESS

        logging.info("my multisig address is %s" % self.oracle_address)
        logging.info("my pubkey: %r" %
                     self.btc.validate_address(self.oracle_address)['pubkey'])

        logging.debug("awaiting requests...")
        count = 0

        while True:
            # Proceed all requests
            requests = self.communication.get_new_requests()
            if len(requests) == 0:
                count = count + 1
                if count > 30:
                    logging.debug("{0} new requests".format(len(requests)))
                    count = 0
            else:
                logging.debug("{0} new requests".format(len(requests)))

            for request in requests:
                self.handle_request(request)
                self.communication.mark_request_done(request)

            task = self.task_queue.get_oldest_task()
            while task is not None:
                self.handle_task(task)
                self.task_queue.done(task)
                task = self.task_queue.get_oldest_task()

            time.sleep(1)
示例#2
0
文件: oracle.py 项目: bencxr/orisi
class Oracle:
  def __init__(self):

    self.db = OracleDb()
    self.btc = BitcoinClient()
    self.kv = KeyValue(self.db)

    self.task_queue = TaskQueue(self.db)

    self.handlers = op_handlers
    self.signer = TransactionSigner(self)

    last_received = self.kv.get_by_section_key('fastcast', 'last_epoch')
    if not last_received:
      self.kv.store('fastcast', 'last_epoch', {'last':0})

    self.set_fastcast_address()

  def set_fastcast_address(self):
    if self.kv.exists('fastcast', 'address'):
      return

    pub, priv = generateKey()
    self.kv.store('fastcast', 'address', {"pub": pub, "priv": priv})

  def broadcast_with_fastcast(self, message):
    data = self.kv.get_by_section_key('fastcast', 'address')
    pub = data['pub']
    priv = data['priv']

    broadcastMessage(message, pub, priv)

  def handle_request(self, request):
    logging.debug(request)
    operation, message = request

    if not operation in self.handlers:
      logging.debug("operation {} not supported".format(operation))
      return

    handler = self.handlers[operation]

    try:
      message.message = json.loads(message.message)
      if 'message_id' in message.message:
        logging.info('parsing message_id: %r' % message.message['message_id'])
      handler(self).handle_request(message)
    except:
      logging.debug(message)
      logging.exception('error handling the request')


    # Save object to database for future reference
    db_class = self.db.operations[operation]
    if db_class:
      db_class(self.db).save(message)

  def get_last_block_number(self):
    val = KeyValue(self.db).get_by_section_key('blocks', 'last_block_number')
    if not val:
      return 0

    last_block = val['last_block']
    return last_block

  def set_last_block(self):
    last_block_number = self.btc.get_block_count()

    # We need to satisfy a condition on looking only for blocks with at
    # least CONFIRMATIONS of confirmations
    satisfied = False

    while not satisfied:
      block_hash = self.btc.get_block_hash(last_block_number)
      block = self.btc.get_block(block_hash)
      if block['confirmations'] >= CONFIRMATIONS:
        satisfied = True
      else:
        last_block_number -= 1

    KeyValue(self.db).store('blocks', 'last_block_number', {'last_block':last_block_number})
    return last_block_number

  def get_new_block(self):
    last_block_number = self.get_last_block_number()

    if last_block_number == 0:
      last_block_number = self.set_last_block()

    newer_block = last_block_number + 1

    block_hash = self.btc.get_block_hash(newer_block)
    if not block_hash:
      return None

    block = self.btc.get_block(block_hash)

    # We are waiting for enough confirmations
    if block['confirmations'] < CONFIRMATIONS:
      return None

    logging.info("New block {}".format(newer_block))
    return block

  def handle_task(self, task):
    operation = task['operation']

    assert(operation in self.handlers)
    handler = self.handlers[operation]
    handler(self).handle_task(task)

    operation = task['operation']
    handler = self.handlers[operation]
    if handler:
      if handler(self).valid_task(task):
        return task
      else:
        logging.debug('Task marked as invalid by handler')
        self.task_queue.done(task)
        return None
    else:
      logging.debug("Task has invalid operation")
      self.task_queue.done(task)
      return None

  def is_fee_sufficient(self, addr, fee):
    if addr != self.oracle_address:
      return False
    if fee < Decimal(ORACLE_FEE):
      return False
    return True

  def prepare_request(self, request):
    try:
      fmsg = FastcastMessage(request)
    except:
      raise FastcastProtocolError()

    msg_body = json.loads(fmsg.message)

    if not 'operation' in msg_body:
      raise MissingOperationError()

    operation = msg_body['operation']
    return (operation, fmsg)

  def filter_requests(self, old_req):
    new_req = []

    last_received = self.kv.get_by_section_key('fastcast','last_epoch')['last']

    max_received = last_received

    for r in old_req:
      received_epoch = int(r['epoch'])
      if received_epoch > last_received:
        new_req.append(r)
        max_received = max(max_received, received_epoch)

    if len(new_req) > 0:
      self.kv.update('fastcast', 'last_epoch', {'last':max_received})

    return new_req

  def run(self):

    if not ORACLE_ADDRESS:
      self.oracle_address = self.kv.get_by_section_key('config','ORACLE_ADDRESS')

      if self.oracle_address is None:
        new_addr = self.btc.server.getnewaddress()
        self.oracle_address = new_addr
        logging.error("created a new address: '%s'" % new_addr)
        self.kv.store('config','ORACLE_ADDRESS',new_addr)
    else:
      self.oracle_address = ORACLE_ADDRESS

    logging.info("my multisig address is %s" % self.oracle_address)
    logging.info( "my pubkey: %r" % self.btc.validate_address(self.oracle_address)['pubkey'] )

    while True:
      # Proceed all requests
      requests = getMessages()
      requests = requests['results']

      requests = self.filter_requests(requests)

      for prev_request in requests:
        try:
          request = self.prepare_request(prev_request)
        except MissingOperationError:
          logging.info('message doesn\'t have operation field, invalid')
          logging.info(prev_request)
          continue
        except FastcastProtocolError:
          logging.info('message does not have all required fields')
          logging.info(prev_request)
          continue
        self.handle_request(request)


      task = self.task_queue.get_oldest_task()
      while task is not None:
        self.handle_task(task)
        self.task_queue.done(task)
        task = self.task_queue.get_oldest_task()

      new_block = self.get_new_block()

      if new_block:
        handlers = op_handlers.itervalues()

        # Every available handler should get a chance to handle new block
        for h in handlers:
          h(self).handle_new_block(new_block)
        KeyValue(self.db).update('blocks', 'last_block_number', {'last_block':new_block['height']})

      time.sleep(1)
示例#3
0
class Oracle:
    def __init__(self):

        self.db = OracleDb()
        self.btc = BitcoinClient()
        self.kv = KeyValue(self.db)

        self.task_queue = TaskQueue(self.db)

        self.handlers = op_handlers
        self.signer = TransactionSigner(self)

        last_received = self.kv.get_by_section_key('fastcast', 'last_epoch')
        if not last_received:
            self.kv.store('fastcast', 'last_epoch', {'last': 0})

        if not self.kv.exists('fastcast', 'address'):
            pub, priv = generateKey()
            self.kv.store('fastcast', 'address', {"pub": pub, "priv": priv})

        logging.info('fastcast pubkey: %r' %
                     self.kv.get_by_section_key('fastcast', 'address')['pub'])

    def broadcast_with_fastcast(self, message):
        data = self.kv.get_by_section_key('fastcast', 'address')
        pub = data['pub']
        priv = data['priv']

        broadcastMessage(message, pub, priv)

    def handle_request(self, request):
        logging.debug(request)
        operation, message = request

        if not operation in self.handlers:
            logging.debug("operation {} not supported".format(operation))
            return

        handler = self.handlers[operation]

        try:
            message.message = json.loads(message.message)
            if 'message_id' in message.message:
                logging.info('parsing message_id: %r' %
                             message.message['message_id'])
            handler(self).handle_request(message)
        except:
            logging.debug(message)
            logging.exception('error handling the request')

        # Save object to database for future reference
        db_class = self.db.operations[operation]
        if db_class:
            db_class(self.db).save(message)

    def get_last_block_number(self):
        val = KeyValue(self.db).get_by_section_key('blocks',
                                                   'last_block_number')
        if not val:
            return 0

        last_block = val['last_block']
        return last_block

    def set_last_block(self):
        last_block_number = self.btc.get_block_count()

        # We need to satisfy a condition on looking only for blocks with at
        # least CONFIRMATIONS of confirmations
        satisfied = False

        while not satisfied:
            block_hash = self.btc.get_block_hash(last_block_number)
            block = self.btc.get_block(block_hash)
            if block['confirmations'] >= CONFIRMATIONS:
                satisfied = True
            else:
                last_block_number -= 1
                print "not enough confirmations - checking previous block %r" % last_block_number

        KeyValue(self.db).store('blocks', 'last_block_number',
                                {'last_block': last_block_number})
        return last_block_number

    def get_new_block(self):
        last_block_number = self.get_last_block_number()

        logging.debug("last_block_number: %r" % last_block_number)

        if last_block_number == 0:
            last_block_number = self.set_last_block()

        newer_block = last_block_number + 1

        block_hash = self.btc.get_block_hash(newer_block)

        logging.info("block hash: %r" % block_hash)
        if not block_hash:
            return None

        block = self.btc.get_block(block_hash)

        # We are waiting for enough confirmations
        if block['confirmations'] < CONFIRMATIONS:
            return None

        logging.info("New block {}".format(newer_block))
        return block

    def handle_task(self, task):
        operation = task['operation']

        assert (operation in self.handlers)
        handler = self.handlers[operation]
        handler(self).handle_task(task)

        operation = task['operation']
        handler = self.handlers[operation]
        if handler:
            if handler(self).valid_task(task):
                return task
            else:
                logging.debug('Task marked as invalid by handler')
                self.task_queue.done(task)
                return None
        else:
            logging.debug("Task has invalid operation")
            self.task_queue.done(task)
            return None

    def is_fee_sufficient(self, addr, fee):
        if addr != self.oracle_address:
            return False
        if fee < Decimal(ORACLE_FEE):
            return False
        return True

    def prepare_request(self, request):
        try:
            fmsg = FastcastMessage(request)
        except:
            raise FastcastProtocolError()

        msg_body = json.loads(fmsg.message)

        if not 'operation' in msg_body:
            raise MissingOperationError()

        operation = msg_body['operation']
        return (operation, fmsg)

    def filter_requests(self, old_req):
        new_req = []

        last_received = self.kv.get_by_section_key('fastcast',
                                                   'last_epoch')['last']

        max_received = last_received

        for r in old_req:
            received_epoch = int(r['epoch'])
            if received_epoch > last_received:
                new_req.append(r)
                max_received = max(max_received, received_epoch)

        if len(new_req) > 0:
            self.kv.update('fastcast', 'last_epoch', {'last': max_received})

        return new_req

    def run(self):

        if not ORACLE_ADDRESS:
            self.oracle_address = self.kv.get_by_section_key(
                'config', 'ORACLE_ADDRESS')

            if self.oracle_address is None:
                new_addr = self.btc.server.getnewaddress()
                self.oracle_address = new_addr
                logging.error("created a new address: '%s'" % new_addr)
                self.kv.store('config', 'ORACLE_ADDRESS', new_addr)
        else:
            self.oracle_address = ORACLE_ADDRESS

        logging.info("my fee: %r" % ORACLE_FEE)
        logging.info("my bitcoin address is %s" % self.oracle_address)
        logging.info("my bitcoin pubkey: %r" %
                     self.btc.validate_address(self.oracle_address)['pubkey'])

        while True:
            # Proceed all requests
            requests = getMessages()
            requests = requests['results']

            requests = self.filter_requests(requests)

            for prev_request in requests:
                try:
                    request = self.prepare_request(prev_request)
                except MissingOperationError:
                    logging.info(
                        'message doesn\'t have operation field, invalid')
                    logging.info(prev_request)
                    continue
                except FastcastProtocolError:
                    logging.info('message does not have all required fields')
                    logging.info(prev_request)
                    continue
                self.handle_request(request)

            task = self.task_queue.get_oldest_task()
            while task is not None:
                self.handle_task(task)
                self.task_queue.done(task)
                task = self.task_queue.get_oldest_task()

            try:
                new_block = self.get_new_block()
            except:
                new_block = None
                logging.exception('problematic block!')

            if new_block:
                handlers = op_handlers.iteritems()

                addresses_per_handler = {}
                all_addresses = set()

                # Every handler can wait for transactions occuring on some addresses
                for name, handler in handlers:
                    addresses = handler(self).get_observed_addresses()
                    addresses_per_handler[name] = addresses
                    for address in addresses:
                        all_addresses.add(address)

                transactions = self.btc.get_transactions_from_block(
                    new_block, list(all_addresses))

                handlers = op_handlers.iteritems()
                for name, handler in handlers:
                    addresses = addresses_per_handler[name]
                    handler_transactions = []
                    for address in addresses:
                        if address in transactions:
                            handler_transactions.extend(transactions[address])
                    handler(self).handle_new_transactions(handler_transactions)

                KeyValue(self.db).update('blocks', 'last_block_number',
                                         {'last_block': new_block['height']})

            time.sleep(10)
示例#4
0
文件: oracle.py 项目: Gricha/orisi
class Oracle:
  def __init__(self):
    self.communication = OracleCommunication()
    self.db = OracleDb()
    self.btc = BitcoinClient()
    self.kv = KeyValue(self.db)

    self.task_queue = TaskQueue(self.db)

    self.handlers = op_handlers
    self.signer = TransactionSigner(self)

  def handle_request(self, request):
    logging.debug(request)
    operation, message = request

    if not operation in self.handlers:
      logging.debug("operation {} not supported".format(operation))
      return

    handler = self.handlers[operation]

    try:
      message.message = json.loads(message.message)
      if 'message_id' in message.message:
        logging.info('parsing message_id: %r' % message.message['message_id'])
      handler(self).handle_request(message)
    except:
      logging.debug(message)
      logging.exception('error handling the request')


    # Save object to database for future reference
    db_class = self.db.operations[operation]
    if db_class:
      db_class(self.db).save(message)

  def handle_task(self, task):
    operation = task['operation']
    assert(operation in self.handlers)
    handler = self.handlers[operation]
    handler(self).handle_task(task)

    operation = task['operation']
    handler = self.handlers[operation]
    if handler:
      if handler(self).valid_task(task):
        return task
      else:
        logging.debug('Task marked as invalid by handler')
        self.task_queue.done(task)
        return None
    else:
      logging.debug("Task has invalid operation")
      self.task_queue.done(task)
      return None

  def is_fee_sufficient(self, addr, fee):
    if addr != self.oracle_address:
      return False
    if fee < Decimal(ORACLE_FEE):
      return False
    return True

  def run(self):

    if not ORACLE_ADDRESS:
      self.oracle_address = self.kv.get_by_section_key('config','ORACLE_ADDRESS')

      if self.oracle_address is None:
        new_addr = self.btc.server.getnewaddress()
        self.oracle_address = new_addr
        logging.error("created a new address: '%s'" % new_addr)
        self.kv.store('config','ORACLE_ADDRESS',new_addr)
    else:
      self.oracle_address = ORACLE_ADDRESS

    logging.info("my multisig address is %s" % self.oracle_address)
    logging.info( "my pubkey: %r" % self.btc.validate_address(self.oracle_address)['pubkey'] )

    logging.debug("awaiting requests...")
    count = 0

    while True:
      # Proceed all requests
      requests = self.communication.get_new_requests()
      if len(requests) == 0:
        count = count + 1
        if count > 30:
            logging.debug("{0} new requests".format(len(requests)))
            count = 0
      else:
        logging.debug("{0} new requests".format(len(requests)))

      for request in requests:
        self.handle_request(request)
        self.communication.mark_request_done(request)

      task = self.task_queue.get_oldest_task()
      while task is not None:
        self.handle_task(task)
        self.task_queue.done(task)
        task = self.task_queue.get_oldest_task()


      time.sleep(1)