Exemple #1
0
def workerdispute(multi, identity, defaults, dry_run):
    """
    File a dispute (as a worker).

    If you are a worker, file a dispute because the creator is
    unresponsive or does not accept work that fulfills the job
    specification, they would use this command to file a dispute.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Dispute Offer':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    valid_results = []

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    valid_results = filter_and_parse_valid_sigs(rein, contents)
    
    if len(valid_results) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(valid_results, 'Job ID', form)
    else:
        doc = dispute_prompt(rein, valid_results, 'Deliverables')
    if not doc:
        return

    log.info('got in-process job for dispute')
    fields = [
                {'label': 'Job name',                       'value_from': doc},
                {'label': 'Job ID',                         'value_from': doc},
                {'label': 'Dispute detail',                 'not_null': form},
                {'label': 'Primary escrow redeem script',   'value_from': doc},
                {'label': 'Mediator escrow redeem script',  'value_from': doc},
             ]
    document = assemble_document('Dispute Offer', fields)
    res = sign_and_store_document(rein, 'workerdispute', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Dispute signed by worker. Run 'rein sync' to push to available servers.")
    log.info('workerdispute signed') if res else log.error('workerdispute failed')
Exemple #2
0
def workerdispute(multi, identity, defaults, dry_run):
    """
    File a dispute (as a worker).

    If you are a worker, file a dispute because the creator is
    unresponsive or does not accept work that fulfills the job
    specification, they would use this command to file a dispute.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Dispute Offer':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    valid_results = []

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    valid_results = filter_and_parse_valid_sigs(rein, contents)
    
    if len(valid_results) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(valid_results, 'Job ID', form)
    else:
        doc = dispute_prompt(rein, valid_results, 'Deliverables')
    if not doc:
        return

    log.info('got in-process job for dispute')
    fields = [
                {'label': 'Job name',                       'value_from': doc},
                {'label': 'Job ID',                         'value_from': doc},
                {'label': 'Dispute detail',                 'not_null': form},
                {'label': 'Primary escrow redeem script',   'value_from': doc},
                {'label': 'Mediator escrow redeem script',  'value_from': doc},
             ]
    document = assemble_document('Dispute Offer', fields)
    res = sign_and_store_document(rein, 'workerdispute', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Dispute signed by worker. Run 'rein sync' to push to available servers.")
    log.info('workerdispute signed') if res else log.error('workerdispute failed')
Exemple #3
0
def post(multi, identity, defaults, dry_run):
    """
    Post a job.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Job':
            return click.echo("Input file type: " + form['Title'])

    store = False if dry_run else True

    eligible_mediators = []
    for url in urls:
        log.info("Querying %s for mediators..." % url)
        sel_url = "{0}query?owner={1}&query=mediators&testnet={2}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        if len(data['mediators']) == 0:
            click.echo('None found')
        eligible_mediators += filter_and_parse_valid_sigs(rein, data['mediators'])

    if 'Mediator public key' in form.keys():
        mediator = select_by_form(eligible_mediators, 'Mediator public key', form)
    else:
        mediator = mediator_prompt(rein, eligible_mediators)
    if not mediator:
        return
    click.echo("Chosen mediator: " + str(mediator['User']))

    log.info('got user and key for post')
    job_guid = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(20))
    fields = [
                {'label': 'Job name',                       'not_null': form},
                {'label': 'Job ID',                         'value': job_guid},
                {'label': 'Category',                       'not_null': form},
                {'label': 'Description',                    'not_null': form},
                {'label': 'Mediator',                       'value': mediator['User']},
                {'label': 'Mediator contact',               'value': mediator['Contact']},
                {'label': 'Mediator public key',            'value': mediator['Mediator public key']},
                {'label': 'Mediator master address',        'value': mediator['Master signing address']},
                {'label': 'Job creator',                    'value': user.name},
                {'label': 'Job creator contact',            'value': user.contact},
                {'label': 'Job creator public key',         'value': key},
                {'label': 'Job creator master address',     'value': user.maddr},
             ]
    document = assemble_document('Job', fields)
    res = sign_and_store_document(rein, 'job_posting', document, user.daddr, user.dkey, store)
    if res and store:
            click.echo("Posting created. Run 'rein sync' to push to available servers.")
    log.info('posting signed') if res else log.error('posting failed')
Exemple #4
0
def resolve(multi, identity, defaults, dry_run):
    """
    Resolve a dispute.

    For mediators who are party to a disputed transaction, this
    command enables you to review those transactions and post
    the decision and signed payments.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Dispute Resolution':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    valid_results = []
    for url in urls:
        log.info("Querying %s for jobs we're mediating..." % url)
        sel_url = "{0}query?owner={1}&query=review&mediator={2}&testnet={3}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, key, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        results = answer.json()['review']
        valid_results += filter_and_parse_valid_sigs(rein, results)

    valid_results = unique(valid_results, 'Job ID')

    job_ids = []
    for result in valid_results:
        if 'Job ID' in result and result['Job ID'] not in job_ids:
            job_ids.append(result['Job ID'])

    job_ids_string = ','.join(job_ids)
    valid_results = []
    for url in urls:
        log.info("Querying %s for %s ..." % (url, job_ids_string))
        sel_url = "{0}query?owner={1}&job_ids={2}&query=by_job_id&testnet={3}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, job_ids_string, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        results = answer.json()
        if 'by_job_id' in results.keys():
            results = results['by_job_id']
        else:
            continue
        valid_results += filter_and_parse_valid_sigs(rein, results, 'Dispute detail')

    valid_results = unique(valid_results, 'Job ID')
    if len(valid_results) == 0:
        click.echo('None found')

    if 'Job ID' in form.keys():
        doc = select_by_form(valid_results, 'Job ID', form)
    else:
        doc = resolve_prompt(rein, valid_results)
    if not doc:
        return

    log.info('got disputes for resolve')
    fields = [
                {'label': 'Job name',                       'value_from': doc},
                {'label': 'Job ID',                         'value_from': doc},
                {'label': 'Resolution',                     'not_null': form},
                {'label': 'Signed primary payment',         'not_null': form},
                {'label': 'Signed mediator payment',        'not_null': form},
             ]
    document = assemble_document('Dispute Resolution', fields)
    res = sign_and_store_document(rein, 'resolve', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Dispute resolution signed by mediator. Run 'rein sync' to push to available servers.")
    log.info('resolve signed') if res else log.error('resolve failed')
Exemple #5
0
def accept(multi, identity, defaults, dry_run):
    """
    Accept a delivery.

    Review and accept deliveries for your jobs. Once a delivery is
    accpted, mediators are advised not to sign any tranasctions
    refunding the job creator.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Accept Delivery':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    valid_results = filter_and_parse_valid_sigs(rein, contents)

    our_orders = []
    for res in valid_results:
        if res['Job creator public key'] == key:
            our_orders.append(res)

    if len(our_orders) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(our_orders, 'Job ID', form)
    else:
        doc = accept_prompt(rein, our_orders, "Deliverables")
    if not doc:
        return

    log.info('got delivery for accept')

    fields = [
                {'label': 'Job name',                       'value_from': doc},
                {'label': 'Job ID',                         'value_from': doc},
                {'label': 'Signed primary payment',         'not_null': form},
                {'label': 'Signed mediator payment',        'not_null': form},
                {'label': 'Primary escrow redeem script',   'value_from': doc},
                {'label': 'Mediator escrow redeem script',  'value_from': doc},
             ]
    document = assemble_document('Accept Delivery', fields)
    click.echo('\n'+document+'\n')
    if click.confirm("Are you sure?"):
        res = sign_and_store_document(rein, 'accept', document, user.daddr, user.dkey, store)
        if res and store:
            click.echo("Accepted delivery. Run 'rein sync' to push to available servers.")
        log.info('accept signed') if res else log.error('accept failed')
    else:
        click.echo("Accept aborted.") 
Exemple #6
0
def deliver(multi, identity, defaults, dry_run):
    """
    Deliver on a job.

    Share deliverables with the creator of the job when completed. In the
    event of a dispute, mediators are advised to review the deliverables
    while deciding how to distribute funds.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Deliver':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    offers = filter_and_parse_valid_sigs(rein, contents)

    not_our_orders = []
    for res in offers:
        if res['Job creator public key'] != key:
            not_our_orders.append(res)

    if len(not_our_orders) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(not_our_orders, 'Job ID', form)
    else:
        doc = delivery_prompt(rein, not_our_orders, 'Deliverables')
    if not doc:
        return

    log.info('got offer for delivery')
    fields = [
                {'label': 'Job name',                       'value_from': doc},
                {'label': 'Job ID',                         'value_from': doc},
                {'label': 'Deliverables',                   'not_null': form},
                {'label': 'Bid amount (BTC)',               'value_from': doc},
                {'label': 'Primary escrow address',         'value_from': doc},
                {'label': 'Mediator escrow address',        'value_from': doc},
                {'label': 'Primary escrow redeem script',   'value_from': doc},
                {'label': 'Mediator escrow redeem script',  'value_from': doc},
                {'label': 'Worker public key',              'value_from': doc},
                {'label': 'Mediator public key',            'value_from': doc},
                {'label': 'Job creator public key',         'value_from': doc},
             ]
    document = assemble_document('Delivery', fields)
    if check_redeem_scripts(document):
        res = sign_and_store_document(rein, 'delivery', document, user.daddr, user.dkey, store)
        if res and store:
            click.echo("Delivery created. Run 'rein sync' to push to available servers.")
    else:
        click.echo("Incorrect redeem scripts. Check keys and their order in redeem script.")
        res = False
    log.info('delivery signed') if res else log.error('delivery failed')
Exemple #7
0
def offer(multi, identity, defaults, dry_run):
    """
    Award a job.

    A job creator would use this command to award the job to a specific bid. 
    Once signed and pushed, escrow addresses should be funded and work can
    begin.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Offer':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    bids = []
    for url in urls:
        log.info("Querying %s for bids on your jobs..." % url)
        sel_url = "{0}query?owner={1}&delegate={2}&query=bids&testnet={3}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, user.daddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        bids += filter_and_parse_valid_sigs(rein, data['bids'])

    unique_bids = unique(bids, 'Description')

    bids = []
    for bid in unique_bids:
        order = Order.get_by_job_id(rein, bid['Job ID'])
        if not order:
            order = Order(bid['Job ID'], testnet=rein.testnet)
            rein.session.add(order)
            rein.session.commit()
        state = order.get_state(rein, Document)
        if state in ['bid', 'job_posting']:
            bids.append(bid)
    
    if len(data['bids']) == 0:
        click.echo('None found')

    if 'Worker public key' in form.keys():
        bid = select_by_form([bid], 'Worker public key', form)
    else:
        bid = bid_prompt(rein, bids)
    if not bid:
        click.echo('None chosen')
        return

    log.info('got bid to offer')
    fields = [
                {'label': 'Job name',                       'value_from': bid},
                {'label': 'Worker',                         'value_from': bid},
                {'label': 'Description',                    'value_from': bid},
                {'label': 'Bid amount (BTC)',               'value_from': bid},
                {'label': 'Primary escrow address',         'value_from': bid},
                {'label': 'Mediator escrow address',        'value_from': bid},
                {'label': 'Job ID',                         'value_from': bid},
                {'label': 'Job creator',                    'value_from': bid},
                {'label': 'Job creator public key',         'value_from': bid},
                {'label': 'Mediator public key',            'value_from': bid},
                {'label': 'Worker public key',              'value_from': bid},
                {'label': 'Primary escrow redeem script',   'value_from': bid},
                {'label': 'Mediator escrow redeem script',  'value_from': bid},
             ]
    document = assemble_document('Offer', fields)
    if not click.confirm('Are you sure you want to award this bid?'):
        return

    res = sign_and_store_document(rein, 'offer', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Offer created. Run 'rein sync' to push to available servers.")
    log.info('offer signed') if res else log.error('offer failed')
Exemple #8
0
def bid(multi, identity, defaults, dry_run):
    """
    Bid on a job.

    Choose from available jobs posted to your registered servers your client knows
    about, and create a bid. Your bid should include the amount of Bitcoin you need
    to complete the job and when you expect to have it complete.
    """
    
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Bid':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    jobs = []
    for url in urls:    
        log.info("Querying %s for jobs..." % url)
        sel_url = "{0}query?owner={1}&query=jobs&testnet={2}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        jobs += filter_and_parse_valid_sigs(rein, data['jobs'])

    unique_jobs = unique(jobs, 'Job ID')

    jobs = []
    for job in unique_jobs:
        order = Order.get_by_job_id(rein, job['Job ID'])
        if not order:
            order = Order(job['Job ID'], testnet=rein.testnet)
            rein.session.add(order)
            rein.session.commit()
        state = order.get_state(rein, Document)
        if state in ['job_posting', 'bid']:
            jobs.append(job)
    
    if len(jobs) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        job = select_by_form(jobs, 'Job ID', form)
    else:
        job = job_prompt(rein, jobs)
    if not job:
        return

    log.info('got job for bid')
    primary_redeem_script, primary_addr = build_2_of_3([job['Job creator public key'],
                                                        job['Mediator public key'],
                                                        key])
    mediator_redeem_script, mediator_escrow_addr = build_mandatory_multisig(job['Mediator public key'],
                                                                            [job['Job creator public key'],key])
    fields = [
                {'label': 'Job name',                       'value_from': job},
                {'label': 'Worker',                         'value': user.name},
                {'label': 'Description',                    'not_null': form},
                {'label': 'Bid amount (BTC)',               'not_null': form},
                {'label': 'Primary escrow address',         'value': primary_addr},
                {'label': 'Mediator escrow address',        'value': mediator_escrow_addr},
                {'label': 'Job ID',                         'value_from': job},
                {'label': 'Job creator',                    'value_from': job},
                {'label': 'Job creator public key',         'value_from': job},
                {'label': 'Mediator public key',            'value_from': job},
                {'label': 'Worker public key',              'value': key},
                {'label': 'Primary escrow redeem script',   'value': primary_redeem_script},
                {'label': 'Mediator escrow redeem script',  'value': mediator_redeem_script},
             ]
    document = assemble_document('Bid', fields)
    res = sign_and_store_document(rein, 'bid', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Bid created. Run 'rein sync' to push to available servers.")
    log.info('bid signed') if res else log.error('bid failed')
Exemple #9
0
def resolve(multi, identity, defaults, dry_run):
    """
    Resolve a dispute.

    For mediators who are party to a disputed transaction, this
    command enables you to review those transactions and post
    the decision and signed payments.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Dispute Resolution':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    valid_results = []
    for url in urls:
        log.info("Querying %s for jobs we're mediating..." % url)
        sel_url = "{0}query?owner={1}&query=review&mediator={2}&testnet={3}"
        try:
            answer = requests.get(
                url=sel_url.format(url, user.maddr, key, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        results = answer.json()['review']
        valid_results += filter_and_parse_valid_sigs(rein, results)

    valid_results = unique(valid_results, 'Job ID')

    job_ids = []
    for result in valid_results:
        if 'Job ID' in result and result['Job ID'] not in job_ids:
            job_ids.append(result['Job ID'])

    job_ids_string = ','.join(job_ids)
    valid_results = []
    for url in urls:
        log.info("Querying %s for %s ..." % (url, job_ids_string))
        sel_url = "{0}query?owner={1}&job_ids={2}&query=by_job_id&testnet={3}"
        try:
            answer = requests.get(url=sel_url.format(
                url, user.maddr, job_ids_string, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        results = answer.json()
        if 'by_job_id' in results.keys():
            results = results['by_job_id']
        else:
            continue
        valid_results += filter_and_parse_valid_sigs(rein, results,
                                                     'Dispute detail')

    valid_results = unique(valid_results, 'Job ID')
    if len(valid_results) == 0:
        click.echo('None found')

    if 'Job ID' in form.keys():
        doc = select_by_form(valid_results, 'Job ID', form)
    else:
        doc = resolve_prompt(rein, valid_results)
    if not doc:
        return

    log.info('got disputes for resolve')
    fields = [
        {
            'label': 'Job name',
            'value_from': doc
        },
        {
            'label': 'Job ID',
            'value_from': doc
        },
        {
            'label': 'Resolution',
            'not_null': form
        },
        {
            'label': 'Signed primary payment',
            'not_null': form
        },
        {
            'label': 'Signed mediator payment',
            'not_null': form
        },
    ]
    document = assemble_document('Dispute Resolution', fields)
    res = sign_and_store_document(rein, 'resolve', document, user.daddr,
                                  user.dkey, store)
    if res and store:
        click.echo(
            "Dispute resolution signed by mediator. Run 'rein sync' to push to available servers."
        )
    log.info('resolve signed') if res else log.error('resolve failed')
Exemple #10
0
def accept(multi, identity, defaults, dry_run):
    """
    Accept a delivery.

    Review and accept deliveries for your jobs. Once a delivery is
    accpted, mediators are advised not to sign any tranasctions
    refunding the job creator.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Accept Delivery':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    valid_results = filter_and_parse_valid_sigs(rein, contents)

    our_orders = []
    for res in valid_results:
        if res['Job creator public key'] == key:
            our_orders.append(res)

    if len(our_orders) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(our_orders, 'Job ID', form)
    else:
        doc = accept_prompt(rein, our_orders, "Deliverables")
    if not doc:
        return

    log.info('got delivery for accept')

    fields = [
        {
            'label': 'Job name',
            'value_from': doc
        },
        {
            'label': 'Job ID',
            'value_from': doc
        },
        {
            'label': 'Signed primary payment',
            'not_null': form
        },
        {
            'label': 'Signed mediator payment',
            'not_null': form
        },
        {
            'label': 'Primary escrow redeem script',
            'value_from': doc
        },
        {
            'label': 'Mediator escrow redeem script',
            'value_from': doc
        },
    ]
    document = assemble_document('Accept Delivery', fields)
    click.echo('\n' + document + '\n')
    if click.confirm("Are you sure?"):
        res = sign_and_store_document(rein, 'accept', document, user.daddr,
                                      user.dkey, store)
        if res and store:
            click.echo(
                "Accepted delivery. Run 'rein sync' to push to available servers."
            )
        log.info('accept signed') if res else log.error('accept failed')
    else:
        click.echo("Accept aborted.")
Exemple #11
0
def deliver(multi, identity, defaults, dry_run):
    """
    Deliver on a job.

    Share deliverables with the creator of the job when completed. In the
    event of a dispute, mediators are advised to review the deliverables
    while deciding how to distribute funds.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Deliver':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    Order.update_orders(rein, Document, get_user_documents)

    documents = []
    orders = Order.get_user_orders(rein, Document)
    for order in orders:
        state = order.get_state(rein, Document)
        if state in ['offer', 'delivery']:
            # get parsed offer for this order and put it in an array
            documents += order.get_documents(rein, Document, state)

    contents = []
    for document in documents:
        contents.append(document.contents)

    offers = filter_and_parse_valid_sigs(rein, contents)

    not_our_orders = []
    for res in offers:
        if res['Job creator public key'] != key:
            not_our_orders.append(res)

    if len(not_our_orders) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        doc = select_by_form(not_our_orders, 'Job ID', form)
    else:
        doc = delivery_prompt(rein, not_our_orders, 'Deliverables')
    if not doc:
        return

    log.info('got offer for delivery')
    fields = [
        {
            'label': 'Job name',
            'value_from': doc
        },
        {
            'label': 'Job ID',
            'value_from': doc
        },
        {
            'label': 'Deliverables',
            'not_null': form
        },
        {
            'label': 'Bid amount (BTC)',
            'value_from': doc
        },
        {
            'label': 'Primary escrow address',
            'value_from': doc
        },
        {
            'label': 'Mediator escrow address',
            'value_from': doc
        },
        {
            'label': 'Primary escrow redeem script',
            'value_from': doc
        },
        {
            'label': 'Mediator escrow redeem script',
            'value_from': doc
        },
        {
            'label': 'Worker public key',
            'value_from': doc
        },
        {
            'label': 'Mediator public key',
            'value_from': doc
        },
        {
            'label': 'Job creator public key',
            'value_from': doc
        },
    ]
    document = assemble_document('Delivery', fields)
    if check_redeem_scripts(document):
        res = sign_and_store_document(rein, 'delivery', document, user.daddr,
                                      user.dkey, store)
        if res and store:
            click.echo(
                "Delivery created. Run 'rein sync' to push to available servers."
            )
    else:
        click.echo(
            "Incorrect redeem scripts. Check keys and their order in redeem script."
        )
        res = False
    log.info('delivery signed') if res else log.error('delivery failed')
Exemple #12
0
def offer(multi, identity, defaults, dry_run):
    """
    Award a job.

    A job creator would use this command to award the job to a specific bid. 
    Once signed and pushed, escrow addresses should be funded and work can
    begin.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Offer':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    bids = []
    for url in urls:
        log.info("Querying %s for bids on your jobs..." % url)
        sel_url = "{0}query?owner={1}&delegate={2}&query=bids&testnet={3}"
        try:
            answer = requests.get(
                url=sel_url.format(url, user.maddr, user.daddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        bids += filter_and_parse_valid_sigs(rein, data['bids'])

    unique_bids = unique(bids, 'Description')

    bids = []
    for bid in unique_bids:
        order = Order.get_by_job_id(rein, bid['Job ID'])
        if not order:
            order = Order(bid['Job ID'], testnet=rein.testnet)
            rein.session.add(order)
            rein.session.commit()
        state = order.get_state(rein, Document)
        if state in ['bid', 'job_posting']:
            bids.append(bid)

    if len(data['bids']) == 0:
        click.echo('None found')

    if 'Worker public key' in form.keys():
        bid = select_by_form([bid], 'Worker public key', form)
    else:
        bid = bid_prompt(rein, bids)
    if not bid:
        click.echo('None chosen')
        return

    log.info('got bid to offer')
    fields = [
        {
            'label': 'Job name',
            'value_from': bid
        },
        {
            'label': 'Worker',
            'value_from': bid
        },
        {
            'label': 'Description',
            'value_from': bid
        },
        {
            'label': 'Bid amount (BTC)',
            'value_from': bid
        },
        {
            'label': 'Primary escrow address',
            'value_from': bid
        },
        {
            'label': 'Mediator escrow address',
            'value_from': bid
        },
        {
            'label': 'Job ID',
            'value_from': bid
        },
        {
            'label': 'Job creator',
            'value_from': bid
        },
        {
            'label': 'Job creator public key',
            'value_from': bid
        },
        {
            'label': 'Mediator public key',
            'value_from': bid
        },
        {
            'label': 'Worker public key',
            'value_from': bid
        },
        {
            'label': 'Primary escrow redeem script',
            'value_from': bid
        },
        {
            'label': 'Mediator escrow redeem script',
            'value_from': bid
        },
    ]
    document = assemble_document('Offer', fields)
    if not click.confirm('Are you sure you want to award this bid?'):
        return

    res = sign_and_store_document(rein, 'offer', document, user.daddr,
                                  user.dkey, store)
    if res and store:
        click.echo(
            "Offer created. Run 'rein sync' to push to available servers.")
    log.info('offer signed') if res else log.error('offer failed')
Exemple #13
0
def bid(multi, identity, defaults, dry_run):
    """
    Bid on a job.

    Choose from available jobs posted to your registered servers your client knows
    about, and create a bid. Your bid should include the amount of Bitcoin you need
    to complete the job and when you expect to have it complete.
    """

    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Bid':
            return click.echo("Input file type: " + form['Title'])
    store = False if dry_run else True

    jobs = []
    for url in urls:
        log.info("Querying %s for jobs..." % url)
        sel_url = "{0}query?owner={1}&query=jobs&testnet={2}"
        try:
            answer = requests.get(
                url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        jobs += filter_and_parse_valid_sigs(rein, data['jobs'])

    unique_jobs = unique(jobs, 'Job ID')

    jobs = []
    for job in unique_jobs:
        order = Order.get_by_job_id(rein, job['Job ID'])
        if not order:
            order = Order(job['Job ID'], testnet=rein.testnet)
            rein.session.add(order)
            rein.session.commit()
        state = order.get_state(rein, Document)
        if state in ['job_posting', 'bid']:
            jobs.append(job)

    if len(jobs) == 0:
        click.echo('None found')
        return

    if 'Job ID' in form.keys():
        job = select_by_form(jobs, 'Job ID', form)
    else:
        job = job_prompt(rein, jobs)
    if not job:
        return

    log.info('got job for bid')
    primary_redeem_script, primary_addr = build_2_of_3(
        [job['Job creator public key'], job['Mediator public key'], key])
    mediator_redeem_script, mediator_escrow_addr = build_mandatory_multisig(
        job['Mediator public key'], [job['Job creator public key'], key])
    fields = [
        {
            'label': 'Job name',
            'value_from': job
        },
        {
            'label': 'Worker',
            'value': user.name
        },
        {
            'label': 'Description',
            'not_null': form
        },
        {
            'label': 'Bid amount (BTC)',
            'not_null': form
        },
        {
            'label': 'Primary escrow address',
            'value': primary_addr
        },
        {
            'label': 'Mediator escrow address',
            'value': mediator_escrow_addr
        },
        {
            'label': 'Job ID',
            'value_from': job
        },
        {
            'label': 'Job creator',
            'value_from': job
        },
        {
            'label': 'Job creator public key',
            'value_from': job
        },
        {
            'label': 'Mediator public key',
            'value_from': job
        },
        {
            'label': 'Worker public key',
            'value': key
        },
        {
            'label': 'Primary escrow redeem script',
            'value': primary_redeem_script
        },
        {
            'label': 'Mediator escrow redeem script',
            'value': mediator_redeem_script
        },
    ]
    document = assemble_document('Bid', fields)
    res = sign_and_store_document(rein, 'bid', document, user.daddr, user.dkey,
                                  store)
    if res and store:
        click.echo(
            "Bid created. Run 'rein sync' to push to available servers.")
    log.info('bid signed') if res else log.error('bid failed')
Exemple #14
0
def post(multi, identity, defaults, dry_run):
    """
    Post a job.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Job':
            return click.echo("Input file type: " + form['Title'])

    store = False if dry_run else True

    eligible_mediators = []
    for url in urls:
        log.info("Querying %s for mediators..." % url)
        sel_url = "{0}query?owner={1}&query=mediators&testnet={2}"
        try:
            answer = requests.get(
                url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        if len(data['mediators']) == 0:
            click.echo('None found')
        eligible_mediators += filter_and_parse_valid_sigs(
            rein, data['mediators'])

    if 'Mediator public key' in form.keys():
        mediator = select_by_form(eligible_mediators, 'Mediator public key',
                                  form)
    else:
        mediator = mediator_prompt(rein, eligible_mediators)
    if not mediator:
        return
    click.echo("Chosen mediator: " + str(mediator['User']))

    log.info('got user and key for post')
    job_guid = ''.join(random.SystemRandom().choice(string.ascii_lowercase +
                                                    string.digits)
                       for _ in range(20))
    fields = [
        {
            'label': 'Job name',
            'not_null': form
        },
        {
            'label': 'Job ID',
            'value': job_guid
        },
        {
            'label': 'Category',
            'not_null': form
        },
        {
            'label': 'Description',
            'not_null': form
        },
        {
            'label': 'Mediator',
            'value': mediator['User']
        },
        {
            'label': 'Mediator contact',
            'value': mediator['Contact']
        },
        {
            'label': 'Mediator public key',
            'value': mediator['Mediator public key']
        },
        {
            'label': 'Mediator master address',
            'value': mediator['Master signing address']
        },
        {
            'label': 'Job creator',
            'value': user.name
        },
        {
            'label': 'Job creator contact',
            'value': user.contact
        },
        {
            'label': 'Job creator public key',
            'value': key
        },
        {
            'label': 'Job creator master address',
            'value': user.maddr
        },
    ]
    document = assemble_document('Job', fields)
    res = sign_and_store_document(rein, 'job_posting', document, user.daddr,
                                  user.dkey, store)
    if res and store:
        click.echo(
            "Posting created. Run 'rein sync' to push to available servers.")
    log.info('posting signed') if res else log.error('posting failed')
Exemple #15
0
def post(multi, identity, defaults, dry_run):
    """
    Post a job.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Job':
            return click.echo("Input file type: " + form['Title'])

    store = False if dry_run else True

    eligible_mediators = []
    for url in urls:
        log.info("Querying %s for mediators..." % url)
        sel_url = "{0}query?owner={1}&query=mediators&testnet={2}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        if len(data['mediators']) == 0:
            click.echo('None found')
        eligible_mediators += filter_and_parse_valid_sigs(rein, data['mediators'])

    if 'Mediator public key' in form.keys():
        mediator = select_by_form(eligible_mediators, 'Mediator public key', form)
    else:
        click.echo("Post a job\n\nFunds for each job in Rein are stored in two multisig addresses. One address\n"
                   "is for the primary payment that will go to the worker on completion. The\n"
                   "second address pays the mediator to be available to resolve a dispute whether\n"
                   "if necessary. The second address should be funded according to the percentage\n"
                   "specified by the mediator and is in addition to the primary payment. The\n"
                   "listing below shows available mediators and the fee they charge. You should\n"
                   "consider the fee as well as any reputational data you are able to find when\n"
                   "choosing a mediator. You choice may affect the number and quality of bids\n"
                   "you receive.\n")
        mediator = mediator_prompt(rein, eligible_mediators)
    if not mediator:
        return
    click.echo("Chosen mediator: " + str(mediator['User']))

    log.info('got user and key for post')
    job_guid = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(20))
    fields = [
                {'label': 'Job name',                       'not_null': form},
                {'label': 'Job ID',                         'value': job_guid},
                {'label': 'Category',                       'not_null': form},
                {'label': 'Description',                    'not_null': form},
                {'label': 'Mediator',                       'value': mediator['User']},
                {'label': 'Mediator contact',               'value': mediator['Contact']},
                {'label': 'Mediator fee',                   'value': mediator['Mediator fee']},
                {'label': 'Mediator public key',            'value': mediator['Mediator public key']},
                {'label': 'Mediator master address',        'value': mediator['Master signing address']},
                {'label': 'Job creator',                    'value': user.name},
                {'label': 'Job creator contact',            'value': user.contact},
                {'label': 'Job creator public key',         'value': key},
                {'label': 'Job creator master address',     'value': user.maddr},
             ]
    document_text = assemble_document('Job', fields)
    document = sign_and_store_document(rein, 'job_posting', document_text, user.daddr, user.dkey, store)
    if document and store:
        click.echo("Posting created. Run 'rein sync' to push to available servers.")
    assemble_order(rein, document)
    log.info('posting signed') if document else log.error('posting failed')
Exemple #16
0
def post(multi, identity, defaults, dry_run):
    """
    Post a job.
    """
    (log, user, key, urls) = init(multi, identity)
    form = {}
    if defaults:
        form = parse_document(open(defaults).read())
        if 'Title' in form and form['Title'] != 'Rein Job':
            return click.echo("Input file type: " + form['Title'])

    store = False if dry_run else True

    eligible_mediators = []
    for url in urls:
        log.info("Querying %s for mediators..." % url)
        sel_url = "{0}query?owner={1}&query=mediators&testnet={2}"
        try:
            answer = requests.get(url=sel_url.format(url, user.maddr, rein.testnet))
        except:
            click.echo('Error connecting to server.')
            log.error('server connect error ' + url)
            continue
        data = answer.json()
        if len(data['mediators']) == 0:
            click.echo('None found')
        eligible_mediators += filter_and_parse_valid_sigs(rein, data['mediators'])

    if 'Mediator public key' in form.keys():
        mediator = select_by_form(eligible_mediators, 'Mediator public key', form)
    else:
        click.echo("Post a job\n\nFunds for each job in Rein are stored in two multisig addresses. One address\n"
                   "is for the primary payment that will go to the worker on completion. The\n"
                   "second address pays the mediator to be available to resolve a dispute whether\n"
                   "if necessary. The second address should be funded according to the percentage\n"
                   "specified by the mediator and is in addition to the primary payment. The\n"
                   "listing below shows available mediators and the fee they charge. You should\n"
                   "consider the fee as well as any reputational data you are able to find when\n"
                   "choosing a mediator. You choice may affect the number and quality of bids\n"
                   "you receive.\n")
        mediator = mediator_prompt(rein, eligible_mediators)
    if not mediator:
        return
    click.echo("Chosen mediator: " + str(mediator['User']))

    log.info('got user and key for post')
    job_guid = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(20))
    fields = [
                {'label': 'Job name',                       'not_null': form},
                {'label': 'Job ID',                         'value': job_guid},
                {'label': 'Category',                       'not_null': form},
                {'label': 'Description',                    'not_null': form},
                {'label': 'Mediator',                       'value': mediator['User']},
                {'label': 'Mediator contact',               'value': mediator['Contact']},
                {'label': 'Mediator fee',                   'value': mediator['Mediator fee']},
                {'label': 'Mediator public key',            'value': mediator['Mediator public key']},
                {'label': 'Mediator master address',        'value': mediator['Master signing address']},
                {'label': 'Job creator',                    'value': user.name},
                {'label': 'Job creator contact',            'value': user.contact},
                {'label': 'Job creator public key',         'value': key},
                {'label': 'Job creator master address',     'value': user.maddr},
             ]
    document = assemble_document('Job', fields)
    res = sign_and_store_document(rein, 'job_posting', document, user.daddr, user.dkey, store)
    if res and store:
        click.echo("Posting created. Run 'rein sync' to push to available servers.")
    log.info('posting signed') if res else log.error('posting failed')