Exemple #1
0
def main(args):
    btc = BitcoinClient()
    tmp_address = btc.validate_address(btc.get_new_address())

    print "fetching charter: %s" % CHARTER_URL
    charter = fetch_charter(CHARTER_URL)

    client_pubkey = tmp_address['pubkey']
    oracle_pubkeys = []
    for o in charter['nodes']:
        #    print json.dumps(o)
        oracle_pubkeys.append(o['pubkey'])

    min_sigs = int(ceil(float(len(oracle_pubkeys)) / 2))

    print "number of nodes: %i" % len(charter['nodes'])
    print "required signatures: %i" % min_sigs
    sum_fees_satoshi = 0
    for o in charter['nodes']:
        sum_fees_satoshi += Decimal(o['fee']) * 100000000
    sum_fees_satoshi += Decimal(charter['org_fee']) * 100000000

    key_list = [client_pubkey] + oracle_pubkeys

    response = btc.create_multisig_address(min_sigs, key_list)

    print ""
    print "1. wire the funds to %s" % response['address']
    print "   oracle & org fees: %i satoshi (as detailed in %s)" % (
        sum_fees_satoshi, CHARTER_URL)
    print "   miners fee: %i satoshi (see MINERS_FEE in src/client/main.py if you want to lower it)" % MINERS_FEE
    print "2. wait for transaction to get any confirmations"
    print "3. run:"
    print "%s main2 %s <locktime_minutes> <return_address>" % (START_COMMAND,
                                                               client_pubkey)
Exemple #2
0
def main(args):
  btc = BitcoinClient()
  tmp_address = btc.validate_address(btc.get_new_address())

  print "fetching charter: %s" % CHARTER_URL
  charter = fetch_charter(CHARTER_URL)

  client_pubkey = tmp_address['pubkey']
  oracle_pubkeys = []
  for o in charter['nodes']:
#    print json.dumps(o)
    oracle_pubkeys.append(o['pubkey'])

  min_sigs = int(ceil(float(len(oracle_pubkeys))/2))

  print "number of nodes: %i" % len(charter['nodes'])
  print "required signatures: %i" % min_sigs
  sum_fees_satoshi = 0
  for o in charter['nodes']:
    sum_fees_satoshi += Decimal(o['fee'])*100000000
  sum_fees_satoshi += Decimal(charter['org_fee'])*100000000


  key_list = [client_pubkey] + oracle_pubkeys

  response = btc.create_multisig_address(min_sigs, key_list)

  print ""
  print "1. wire the funds to %s" % response['address']
  print "   oracle & org fees: %i satoshi (as detailed in %s)" % (sum_fees_satoshi , CHARTER_URL)
  print "   miners fee: %i satoshi (see MINERS_FEE in src/client/main.py if you want to lower it)" % MINERS_FEE
  print "2. wait for transaction to get any confirmations"
  print "3. run:"
  print "%s main2 %s <locktime_minutes> <return_address>" % ( START_COMMAND, client_pubkey )
Exemple #3
0
    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)
Exemple #4
0
def tx_info(args):
    tx = args[0]
    btc = BitcoinClient()

    prevtxs = '[{"redeemScript": "52210281cf9fa9241f0a9799f27a4d5d60cff74f30eed1d536bf7a72d3dec936c151632102e8e22190b0adfefd0962c6332e74ab68831d56d0bfc2b01b32beccd56e3ef6f021035ff60e6745093b9bcbae93082e1c50ca5b3fcf8bcd186a46da46ded5132530522103a9bd3bfbd9f9b1719d3ecad8658796dc5e778177d77145b5c37247eb3060861854ae", "txid": "10a3ab54e1e19701fcb86c7725621b5b1b26415f94363de35a493ba9ca502b15", "vout": 0, "scriptPubKey": "a914a37ce66d7065157037e90ca4d4b4a20d8d865a2687"}]'
    prevtxs = json.loads(prevtxs)

    pprint.pprint(btc.decode_raw_transaction(tx))

    pprint.pprint(btc.signatures_count(tx, prevtxs))

    pprint.pprint(btc.signatures(tx, prevtxs))
Exemple #5
0
def tx_info(args):
  tx = args[0]
  btc = BitcoinClient()

  prevtxs = '[{"redeemScript": "52210281cf9fa9241f0a9799f27a4d5d60cff74f30eed1d536bf7a72d3dec936c151632102e8e22190b0adfefd0962c6332e74ab68831d56d0bfc2b01b32beccd56e3ef6f021035ff60e6745093b9bcbae93082e1c50ca5b3fcf8bcd186a46da46ded5132530522103a9bd3bfbd9f9b1719d3ecad8658796dc5e778177d77145b5c37247eb3060861854ae", "txid": "10a3ab54e1e19701fcb86c7725621b5b1b26415f94363de35a493ba9ca502b15", "vout": 0, "scriptPubKey": "a914a37ce66d7065157037e90ca4d4b4a20d8d865a2687"}]'
  prevtxs = json.loads(prevtxs)

  pprint.pprint( btc.decode_raw_transaction(tx))

  pprint.pprint (btc.signatures_count(tx, prevtxs))

  pprint.pprint (btc.signatures(tx, prevtxs))
Exemple #6
0
    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()
Exemple #7
0
    def __init__(self):
        self.communication = MockBitmessageCommunication()
        self.db = MockOracleDb()
        self.btc = BitcoinClient(account=TEST_ACCOUNT)
        self.evaluator = Evaluator()

        self.task_queue = TaskQueue(self.db)

        self.handlers = defaultdict(lambda: None, handlers)
Exemple #8
0
  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)
Exemple #9
0
    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'])
Exemple #10
0
  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()
Exemple #11
0
  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'])
Exemple #12
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)
Exemple #13
0
def pricecheck_create(args):
  if len(args)<5:
    print "USAGE: `%s pricecheck_create <pubkey_once> <locktime_minutes> <return_address_if_greater> <return_address_if_smaller> <value>`" % START_COMMAND
    print "- run `%s main` to obtain pubkey_once" % START_COMMAND
    print "- keep in mind that this is alpha, don't expect oracles to run properly for any extended periods of time"
    return

  btc = BitcoinClient()

  request = {}
  client_pubkey = args[0]
  request['locktime'] = time.time() + int(args[1])*60
  request['return_if_greater'] = args[2]
  request['return_if_lesser'] = args[3]
  request['price'] = float(args[4])

  print "fetching charter url" # hopefully it didn't check between running main1 and main2
  charter = fetch_charter(CHARTER_URL)

  oracle_pubkeys = []
  oracle_fees = {}
  oracle_bms = []

  for o in charter['nodes']:
    oracle_pubkeys.append(o['pubkey'])
    oracle_fees[o['address']] = o['fee']
    oracle_bms.append(o['bm'])

  oracle_fees[charter['org_address']] = charter['org_fee']

  min_sigs = int(ceil(float(len(oracle_pubkeys))/2))

  key_list = [client_pubkey] + oracle_pubkeys

  response = btc.create_multisig_address(min_sigs, key_list)
  msig_addr = response['address'] # we're using this as an identificator
  redeemScript = response['redeemScript']

  request['message_id'] = "%s-%s" % (msig_addr, str(randrange(1000000000,9000000000)))
  request['pubkey_list'] = key_list

  request['miners_fee_satoshi'] = MINERS_FEE

  print "fetching transactions incoming to %s ..." % msig_addr

  # for production purposes you might want to fetch the data using bitcoind, but that's expensive
  address_json = liburl_wrapper.safe_read("https://blockchain.info/address/%s?format=json" % msig_addr, timeout_time=10)
  try:
    address_history = json.loads(address_json)
  except:
    print "blockchain.info problem"
    print address_json
    return

  prevtxs = []
  sum_satoshi = 0

  for tx in address_history['txs']:
    outputs = []
    if 'out' in tx:
      outputs = outputs + tx['out']
    if 'outputs' in tx:
      outputs = outputs + tx['outputs']

    for vout in tx['out']:
      print vout
      if vout['addr'] == msig_addr:
        prevtx = {
          'scriptPubKey' : vout['script'],
          'vout': vout['n'],
          'txid': tx['hash'],
          'redeemScript': redeemScript,
        }
        sum_satoshi += vout['value']
        prevtxs.append(prevtx)

  if len(prevtxs) == 0:
    print "ERROR: couldn't find transactions sending money to %s" % msig_addr
    return

  request['prevtxs'] = prevtxs
  request['outputs'] = oracle_fees

  request["req_sigs"] = min_sigs
  request['operation'] = 'pricecheck_create'
  request['sum_satoshi'] = sum_satoshi

  bm = BitmessageClient()
  print "sending: %r" % json.dumps(request)
  print bm.chan_address

  request_content = json.dumps(request)

  print bm.send_message(bm.chan_address, request['operation'], request_content)
Exemple #14
0
def main2(args):
    if len(args) < 3:
        print "USAGE: `%s main2 <pubkey_once> <locktime_minutes> <return_address>`" % START_COMMAND
        print "- run `%s main` to obtain pubkey_once" % START_COMMAND
        print "- keep in mind that this is alpha, don't expect oracles to run properly for any extended periods of time"
        return

    btc = BitcoinClient()

    request = {}
    client_pubkey = args[0]
    request['locktime'] = time.time() + int(args[1]) * 60
    request['return_address'] = args[2]

    print "fetching charter url"  # hopefully it didn't check between running main1 and main2
    charter = fetch_charter(CHARTER_URL)

    oracle_pubkeys = []
    oracle_fees = {}
    oracle_bms = []

    for o in charter['nodes']:
        oracle_pubkeys.append(o['pubkey'])
        oracle_fees[o['address']] = o['fee']
        oracle_bms.append(o['bm'])

    oracle_fees[charter['org_address']] = charter['org_fee']

    min_sigs = int(ceil(float(len(oracle_pubkeys)) / 2))

    key_list = [client_pubkey] + oracle_pubkeys

    response = btc.create_multisig_address(min_sigs, key_list)
    msig_addr = response['address']  # we're using this as an identificator
    redeemScript = response['redeemScript']

    request['message_id'] = "%s-%s" % (msig_addr,
                                       str(randrange(1000000000, 9000000000)))
    request['pubkey_list'] = key_list

    request['miners_fee_satoshi'] = MINERS_FEE

    print "fetching transactions incoming to %s ..." % msig_addr

    # for production purposes you might want to fetch the data using bitcoind, but that's expensive
    address_json = liburl_wrapper.safe_read(
        "https://blockchain.info/address/%s?format=json" % msig_addr,
        timeout_time=10)
    try:
        address_history = json.loads(address_json)
    except:
        print "blockchain.info problem"
        print address_json
        return

    prevtxs = []
    sum_satoshi = 0

    for tx in address_history['txs']:
        outputs = []
        if 'out' in tx:
            outputs = outputs + tx['out']
        if 'outputs' in tx:
            outputs = outputs + tx['outputs']

        for vout in tx['out']:
            print vout
            if vout['addr'] == msig_addr:
                prevtx = {
                    'scriptPubKey': vout['script'],
                    'vout': vout['n'],
                    'txid': tx['hash'],
                    'redeemScript': redeemScript,
                }
                sum_satoshi += vout['value']
                prevtxs.append(prevtx)

    if len(prevtxs) == 0:
        print "ERROR: couldn't find transactions sending money to %s" % msig_addr
        return

    request['prevtxs'] = prevtxs
    request['outputs'] = oracle_fees

    request["req_sigs"] = min_sigs
    request['operation'] = 'timelock_create'
    request['sum_satoshi'] = sum_satoshi

    bm = BitmessageClient()
    print "sending: %r" % json.dumps(request)
    print bm.chan_address

    request_content = json.dumps(request)

    print bm.send_message(bm.chan_address, request['operation'],
                          request_content)

    print ""
    print "Gathering oracle responses. It may take BitMessage 30-60 seconds to deliver a message one way."
    print "Although we've seen delays up to half an hour, especially if BitMessage client was just launched."
    print ""

    oracles_confirmed = 0
    while oracle_bms:
        messages = bm.get_unread_messages()
        print "oracles confirmed: {}".format(oracles_confirmed)
        for msg in messages:
            if msg.from_address in oracle_bms:
                try:
                    content = json.loads(msg.message)
                except:
                    print msg.message
                    print 'failed decoding message'
                    continue

                if 'in_reply_to' not in content:
                    continue

                if content['in_reply_to'] == request['message_id']:
                    print "[%r][%r] %r" % (msg.subject, msg.from_address,
                                           msg.message)
                    print ""
                    oracle_bms.remove(msg.from_address)

        if oracle_bms:  #if still awaiting replies from some oracles
            time.sleep(10)
Exemple #15
0
def main2(args):
    if len(args) < 3:
        print "USAGE: `%s main2 <pubkey_once> <locktime_minutes> <return_address>`" % START_COMMAND
        print "- run `%s main` to obtain pubkey_once" % START_COMMAND
        print "- keep in mind that this is alpha, don't expect oracles to run properly for any extended periods of time"
        return

    btc = BitcoinClient()

    request = {}
    client_pubkey = args[0]
    request['locktime'] = time.time() + int(args[1]) * 60
    request['return_address'] = args[2]

    print "fetching charter url"  # hopefully it didn't check between running main1 and main2
    charter = fetch_charter(CHARTER_URL)

    oracle_pubkeys = []
    oracle_fees = {}
    oracle_bms = []

    for o in charter['nodes']:
        oracle_pubkeys.append(o['pubkey'])
        oracle_fees[o['address']] = o['fee']
        #oracle_bms.append(o['bm'])

    oracle_fees[charter['org_address']] = charter['org_fee']

    min_sigs = int(ceil(float(len(oracle_pubkeys)) / 2))

    key_list = [client_pubkey] + oracle_pubkeys

    response = btc.create_multisig_address(min_sigs, key_list)
    msig_addr = response['address']  # we're using this as an identificator
    redeemScript = response['redeemScript']

    request['message_id'] = "%s-%s" % (msig_addr,
                                       str(randrange(1000000000, 9000000000)))
    request['pubkey_list'] = key_list

    request['miners_fee_satoshi'] = MINERS_FEE

    print "fetching transactions incoming to %s ..." % msig_addr

    import requests
    # for production purposes you might want to fetch the data using bitcoind, but that's expensive
    print "get"
    address_json = requests.get(
        "https://blockchain.info/address/%s?format=json" % msig_addr).text
    #try:
    print address_json
    address_history = json.loads(address_json)

    #except:
    #print "blockchain.info problem"
    #print address_json
    #return

    prevtxs = []
    sum_satoshi = 0

    for tx in address_history['txs']:
        outputs = []
        if 'out' in tx:
            outputs = outputs + tx['out']
        if 'outputs' in tx:
            outputs = outputs + tx['outputs']

        for vout in tx['out']:
            print vout
            if vout['addr'] == msig_addr:
                prevtx = {
                    'scriptPubKey': vout['script'],
                    'vout': vout['n'],
                    'txid': tx['hash'],
                    'redeemScript': redeemScript,
                }
                sum_satoshi += vout['value']
                prevtxs.append(prevtx)

    if len(prevtxs) == 0:
        print "ERROR: couldn't find transactions sending money to %s" % msig_addr
        #  return

    request['prevtxs'] = prevtxs
    request['outputs'] = oracle_fees

    request["req_sigs"] = min_sigs
    request['operation'] = 'timelock_create'
    request['sum_satoshi'] = sum_satoshi

    pub, priv = generateKey()

    meta_request = {}
    meta_request['source'] = pub
    meta_request['channel'] = 0
    meta_request['signature'] = 0
    meta_request['body'] = json.dumps(request)

    print sendMessage(constructMessage(priv, **meta_request))
Exemple #16
0
def main2(args):
  if len(args)<3:
    print "USAGE: `%s main2 <pubkey_once> <locktime_minutes> <return_address>`" % START_COMMAND
    print "- run `%s main` to obtain pubkey_once" % START_COMMAND
    print "- keep in mind that this is alpha, don't expect oracles to run properly for any extended periods of time"
    return

  btc = BitcoinClient()

  request = {}
  client_pubkey = args[0]
  request['locktime'] = time.time() + int(args[1])*60
  request['return_address'] = args[2]

  print "fetching charter url" # hopefully it didn't check between running main1 and main2
  charter = fetch_charter(CHARTER_URL)

  oracle_pubkeys = []
  oracle_fees = {}
  oracle_bms = []

  for o in charter['nodes']:
    oracle_pubkeys.append(o['pubkey'])
    oracle_fees[o['address']] = o['fee']
    oracle_bms.append(o['bm'])

  oracle_fees[charter['org_address']] = charter['org_fee']

  min_sigs = int(ceil(float(len(oracle_pubkeys))/2))

  key_list = [client_pubkey] + oracle_pubkeys

  response = btc.create_multisig_address(min_sigs, key_list)
  msig_addr = response['address'] # we're using this as an identificator
  redeemScript = response['redeemScript']

  request['message_id'] = "%s-%s" % (msig_addr, str(randrange(1000000000,9000000000)))
  request['pubkey_list'] = key_list

  request['miners_fee_satoshi'] = MINERS_FEE

  print "fetching transactions incoming to %s ..." % msig_addr

  # for production purposes you might want to fetch the data using bitcoind, but that's expensive
  address_json = liburl_wrapper.safe_read("https://blockchain.info/address/%s?format=json" % msig_addr, timeout_time=10)
  try:
    address_history = json.loads(address_json)
  except:
    print "blockchain.info problem"
    print address_json
    return

  prevtxs = []
  sum_satoshi = 0

  for tx in address_history['txs']:
    outputs = []
    if 'out' in tx:
      outputs = outputs + tx['out']
    if 'outputs' in tx:
      outputs = outputs + tx['outputs']

    for vout in tx['out']:
      print vout
      if vout['addr'] == msig_addr:
        prevtx = {
          'scriptPubKey' : vout['script'],
          'vout': vout['n'],
          'txid': tx['hash'],
          'redeemScript': redeemScript,
        }
        sum_satoshi += vout['value']
        prevtxs.append(prevtx)

  if len(prevtxs) == 0:
    print "ERROR: couldn't find transactions sending money to %s" % msig_addr
    return

  request['prevtxs'] = prevtxs
  request['outputs'] = oracle_fees

  request["req_sigs"] = min_sigs
  request['operation'] = 'timelock_create'
  request['sum_satoshi'] = sum_satoshi

  bm = BitmessageClient()
  print "sending: %r" % json.dumps(request)
  print bm.chan_address

  request_content = json.dumps(request)

  print bm.send_message(bm.chan_address, request['operation'], request_content)

  print ""
  print "Gathering oracle responses. It may take BitMessage 30-60 seconds to deliver a message one way."
  print "Although we've seen delays up to half an hour, especially if BitMessage client was just launched."
  print ""


  oracles_confirmed = 0
  while oracle_bms:
    messages = bm.get_unread_messages()
    print "oracles confirmed: {}".format(oracles_confirmed)
    for msg in messages:
      if msg.from_address in oracle_bms:
        try:
          content = json.loads(msg.message)
        except:
          print msg.message
          print 'failed decoding message'
          continue

        if 'in_reply_to' not in content:
          continue

        if content['in_reply_to'] == request['message_id']:
            print "[%r][%r] %r" % (msg.subject, msg.from_address, msg.message)
            print ""
            oracle_bms.remove(msg.from_address)

    if oracle_bms: #if still awaiting replies from some oracles
      time.sleep(10)
Exemple #17
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)
Exemple #18
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})

    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)
Exemple #19
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)