Пример #1
0
class WeightsSkipList(forest.TrackerSkipList):
    # share_count, weights, total_weight
    
    def get_delta(self, element):
        from p2pool.bitcoin import data as bitcoin_data
        share = self.tracker.items[element]
        att = bitcoin_data.target_to_average_attempts(share.target)
        return 1, {share.new_script: att*(65535-share.share_data['donation'])}, att*65535, att*share.share_data['donation']
    
    def combine_deltas(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2)):
        return share_count1 + share_count2, math.add_dicts(weights1, weights2), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
Пример #2
0
            new_weights = {script: (desired_weight - total_weight1)//65535*weights2[script]//(total_weight2//65535)}
            return share_count1 + share_count2, (weights_list, new_weights), desired_weight, total_donation_weight1 + (desired_weight - total_weight1)//65535*total_donation_weight2//(total_weight2//65535)
        return share_count1 + share_count2, (weights_list, weights2), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
    
    def judge(self, (share_count, weights_list, total_weight, total_donation_weight), (max_shares, desired_weight)):
        if share_count > max_shares or total_weight > desired_weight:
            return 1
        elif share_count == max_shares or total_weight == desired_weight:
            return 0
        else:
            return -1
    
    def finalize(self, (share_count, weights_list, total_weight, total_donation_weight), (max_shares, desired_weight)):
        assert share_count <= max_shares and total_weight <= desired_weight
        assert share_count == max_shares or total_weight == desired_weight
        return math.add_dicts(*math.flatten_linked_list(weights_list)), total_weight, total_donation_weight

class OkayTracker(forest.Tracker):
    def __init__(self, net):
        forest.Tracker.__init__(self, delta_type=forest.get_attributedelta_type(dict(forest.AttributeDelta.attrs,
            work=lambda share: bitcoin_data.target_to_average_attempts(share.target),
            min_work=lambda share: bitcoin_data.target_to_average_attempts(share.max_target),
        )))
        self.net = net
        self.verified = forest.SubsetTracker(delta_type=forest.get_attributedelta_type(dict(forest.AttributeDelta.attrs,
            work=lambda share: bitcoin_data.target_to_average_attempts(share.target),
        )), subset_of=self)
        self.get_cumulative_weights = WeightsSkipList(self)
    
    def attempt_verify(self, share):
        if share.hash in self.verified.items:
Пример #3
0
def generate_transaction(tracker, share_data, block_target, desired_timestamp, net):
    previous_share_hash = share_data['previous_share_hash']
    new_script = share_data['new_script']
    subsidy = share_data['subsidy']
    donation = share_data['donation']
    assert 0 <= donation <= 65535
    
    if len(share_data['coinbase']) > 100:
        raise ValueError('coinbase too long!')
    
    previous_share = tracker.shares[previous_share_hash] if previous_share_hash is not None else None
    
    chain_length = getattr(net, 'REAL_CHAIN_LENGTH_FUNC', lambda _: net.REAL_CHAIN_LENGTH)(previous_share.timestamp if previous_share is not None else None)
    
    height, last = tracker.get_height_and_last(previous_share_hash)
    assert height >= chain_length or last is None
    if height < net.TARGET_LOOKBEHIND:
        bits = bitcoin_data.FloatingInteger.from_target_upper_bound(net.MAX_TARGET)
    else:
        attempts_per_second = get_pool_attempts_per_second(tracker, previous_share_hash, net.TARGET_LOOKBEHIND)
        pre_target = 2**256//(net.SHARE_PERIOD*attempts_per_second) - 1
        pre_target2 = math.clip(pre_target, (previous_share.target*9//10, previous_share.target*11//10))
        pre_target3 = math.clip(pre_target2, (0, net.MAX_TARGET))
        bits = bitcoin_data.FloatingInteger.from_target_upper_bound(pre_target3)
    
    attempts_to_block = bitcoin_data.target_to_average_attempts(block_target)
    max_att = net.SPREAD * attempts_to_block
    
    this_att = min(bitcoin_data.target_to_average_attempts(bits.target), max_att)
    other_weights, other_total_weight, other_donation_weight = tracker.get_cumulative_weights(previous_share_hash, min(height, chain_length), 65535*max(0, max_att - this_att))
    assert other_total_weight == sum(other_weights.itervalues()) + other_donation_weight, (other_total_weight, sum(other_weights.itervalues()) + other_donation_weight)
    weights, total_weight, donation_weight = math.add_dicts({new_script: this_att*(65535-donation)}, other_weights), this_att*65535 + other_total_weight, this_att*donation + other_donation_weight
    assert total_weight == sum(weights.itervalues()) + donation_weight, (total_weight, sum(weights.itervalues()) + donation_weight)
    
    SCRIPT = '4104ffd03de44a6e11b9917f3a29f9443283d9871c9d743ef30d5eddcd37094b64d1b3d8090496b53256786bf5c82932ec23c3b74d9f05a6f95a8b5529352656664bac'.decode('hex')
    
    # 1 satoshi is always donated so that a list of p2pool generated blocks can be easily found by looking at the donation address
    amounts = dict((script, (subsidy-1)*(199*weight)//(200*total_weight)) for (script, weight) in weights.iteritems())
    amounts[new_script] = amounts.get(new_script, 0) + (subsidy-1)//200
    amounts[SCRIPT] = amounts.get(SCRIPT, 0) + (subsidy-1)*(199*donation_weight)//(200*total_weight)
    amounts[SCRIPT] = amounts.get(SCRIPT, 0) + subsidy - sum(amounts.itervalues()) # collect any extra satoshis :P
    
    if sum(amounts.itervalues()) != subsidy:
        raise ValueError()
    if any(x < 0 for x in amounts.itervalues()):
        raise ValueError()
    
    dests = sorted(amounts.iterkeys(), key=lambda script: (amounts[script], script))
    dests = dests[-4000:] # block length limit, unlikely to ever be hit
    
    share_info = dict(
        share_data=share_data,
        bits=bits,
        timestamp=math.clip(desired_timestamp, (previous_share.timestamp - 60, previous_share.timestamp + 60)) if previous_share is not None else desired_timestamp,
    )
    
    return share_info, dict(
        version=1,
        tx_ins=[dict(
            previous_output=None,
            sequence=None,
            script=share_data['coinbase'].ljust(2, '\x00'),
        )],
        tx_outs=[dict(value=0, script='\x20' + pack.IntType(256).pack(bitcoin_data.hash256(share_info_type.pack(share_info))))] + [dict(value=amounts[script], script=script) for script in dests if amounts[script]],
        lock_time=0,
    )
Пример #4
0
    
    def combine_deltas(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2)):
        return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
    
    def initial_solution(self, start, (max_shares, desired_weight)):
        assert desired_weight % 65535 == 0, divmod(desired_weight, 65535)
        return 0, {}, 0, 0
    
    def apply_delta(self, (share_count1, weights1, total_weight1, total_donation_weight1), (share_count2, weights2, total_weight2, total_donation_weight2), (max_shares, desired_weight)):
        if total_weight1 + total_weight2 > desired_weight and share_count2 == 1:
            script, = weights2.iterkeys()
            new_weights = dict(weights1)
            assert (desired_weight - total_weight1) % 65535 == 0
            new_weights[script] = new_weights.get(script, 0) + (desired_weight - total_weight1)//65535*weights2[script]//(total_weight2//65535)
            return share_count1 + share_count2, new_weights, desired_weight, total_donation_weight1 + (desired_weight - total_weight1)//65535*total_donation_weight2//(total_weight2//65535)
        return share_count1 + share_count2, math.add_dicts([weights1, weights2]), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2
    
    def judge(self, (share_count, weights, total_weight, total_donation_weight), (max_shares, desired_weight)):
        if share_count > max_shares or total_weight > desired_weight:
            return 1
        elif share_count == max_shares or total_weight == desired_weight:
            return 0
        else:
            return -1
    
    def finalize(self, (share_count, weights, total_weight, total_donation_weight)):
        return weights, total_weight, total_donation_weight

class CountsSkipList(skiplist.SkipList):
    # share_count, counts, total_count
    
Пример #5
0
def generate_transaction(tracker, previous_share_hash, new_script, subsidy, nonce, block_target, net):
    height, last = tracker.get_height_and_last(previous_share_hash)
    if height < net.TARGET_LOOKBEHIND:
        target = bitcoin_data.FloatingIntegerType().truncate_to(2**256//2**20 - 1)
    else:
        attempts_per_second = get_pool_attempts_per_second(tracker, previous_share_hash, net)
        pre_target = 2**256//(net.SHARE_PERIOD*attempts_per_second) - 1
        previous_share = tracker.shares[previous_share_hash] if previous_share_hash is not None else None
        pre_target2 = math.clip(pre_target, (previous_share.target*9//10, previous_share.target*11//10))
        pre_target3 = math.clip(pre_target2, (0, net.MAX_TARGET))
        target = bitcoin_data.FloatingIntegerType().truncate_to(pre_target3)
    
    attempts_to_block = bitcoin_data.target_to_average_attempts(block_target)
    max_weight = net.SPREAD * attempts_to_block
    
    '''
    class fake_share(object):
        pass
    fake_share.new_script = new_script
    fake_share.target = target
    
    dest_weights = {}
    total_weight = 0
    for share in itertools.chain([fake_share], itertools.islice(tracker.get_chain_to_root(previous_share_hash), net.CHAIN_LENGTH)):
        weight = bitcoin_data.target_to_average_attempts(share.target)
        if weight > max_weight - total_weight:
            weight = max_weight - total_weight
        
        dest_weights[share.new_script] = dest_weights.get(share.new_script, 0) + weight
        total_weight += weight
        
        if total_weight == max_weight:
            break
    '''
    
    this_weight = min(bitcoin_data.target_to_average_attempts(target), max_weight)
    other_weights, other_weights_total = tracker.get_cumulative_weights(previous_share_hash, min(height, net.CHAIN_LENGTH), max(0, max_weight - this_weight))
    dest_weights, total_weight = math.add_dicts([{new_script: this_weight}, other_weights]), this_weight + other_weights_total
    total_weight = sum(dest_weights.itervalues())
    
    amounts = dict((script, subsidy*(396*weight)//(400*total_weight)) for (script, weight) in dest_weights.iteritems())
    amounts[new_script] = amounts.get(new_script, 0) + subsidy*2//400
    amounts[net.SCRIPT] = amounts.get(net.SCRIPT, 0) + subsidy*2//400
    amounts[net.SCRIPT] = amounts.get(net.SCRIPT, 0) + subsidy - sum(amounts.itervalues()) # collect any extra
    if sum(amounts.itervalues()) != subsidy:
        raise ValueError()
    if any(x < 0 for x in amounts.itervalues()):
        raise ValueError()
    
    pre_dests = sorted(amounts.iterkeys(), key=lambda script: (amounts[script], script))
    pre_dests = pre_dests[-4000:] # block length limit, unlikely to ever be hit
    
    dests = sorted(pre_dests, key=lambda script: (script == new_script, script))
    assert dests[-1] == new_script
    
    return dict(
        version=1,
        tx_ins=[dict(
            previous_output=None,
            sequence=None,
            script=coinbase_type.pack(dict(
                identifier=net.IDENTIFIER,
                share_data=dict(
                    previous_share_hash=previous_share_hash,
                    nonce=nonce,
                    target=target,
                ),
            )),
        )],
        tx_outs=[dict(value=amounts[script], script=script) for script in dests if amounts[script]],
        lock_time=0,
    )
Пример #6
0
                           total_donation_weight1),
                    (share_count2, weights2, total_weight2,
                     total_donation_weight2), (max_shares, desired_weight)):
        if total_weight1 + total_weight2 > desired_weight and share_count2 == 1:
            script, = weights2.iterkeys()
            new_weights = dict(weights1)
            assert (desired_weight - total_weight1) % 65535 == 0
            new_weights[script] = new_weights.get(
                script,
                0) + (desired_weight - total_weight1
                      ) // 65535 * weights2[script] // (total_weight2 // 65535)
            return share_count1 + share_count2, new_weights, desired_weight, total_donation_weight1 + (
                desired_weight - total_weight1
            ) // 65535 * total_donation_weight2 // (total_weight2 // 65535)
        return share_count1 + share_count2, math.add_dicts(
            [weights1, weights2]
        ), total_weight1 + total_weight2, total_donation_weight1 + total_donation_weight2

    def judge(self, (share_count, weights, total_weight,
                     total_donation_weight), (max_shares, desired_weight)):
        if share_count > max_shares or total_weight > desired_weight:
            return 1
        elif share_count == max_shares or total_weight == desired_weight:
            return 0
        else:
            return -1

    def finalize(self, (share_count, weights, total_weight,
                        total_donation_weight)):
        return weights, total_weight, total_donation_weight
Пример #7
0
def generate_transaction(tracker, share_data, block_target, desired_timestamp,
                         net):
    previous_share_hash = share_data['previous_share_hash']
    new_script = share_data['new_script']
    subsidy = share_data['subsidy']
    donation = share_data['donation']
    assert 0 <= donation <= 65535

    if len(share_data['coinbase']) > 100:
        raise ValueError('coinbase too long!')

    previous_share = tracker.shares[
        previous_share_hash] if previous_share_hash is not None else None

    chain_length = getattr(
        net, 'REAL_CHAIN_LENGTH_FUNC', lambda _: net.REAL_CHAIN_LENGTH)(
            previous_share.timestamp if previous_share is not None else None)

    height, last = tracker.get_height_and_last(previous_share_hash)
    assert height >= chain_length or last is None
    if height < net.TARGET_LOOKBEHIND:
        target = bitcoin_data.FloatingInteger.from_target_upper_bound(
            net.MAX_TARGET)
    else:
        attempts_per_second = get_pool_attempts_per_second(
            tracker, previous_share_hash, net.TARGET_LOOKBEHIND)
        pre_target = 2**256 // (net.SHARE_PERIOD * attempts_per_second) - 1
        pre_target2 = math.clip(pre_target, (previous_share.target * 9 // 10,
                                             previous_share.target * 11 // 10))
        pre_target3 = math.clip(pre_target2, (0, net.MAX_TARGET))
        target = bitcoin_data.FloatingInteger.from_target_upper_bound(
            pre_target3)

    attempts_to_block = bitcoin_data.target_to_average_attempts(block_target)
    max_att = net.SPREAD * attempts_to_block

    this_att = min(bitcoin_data.target_to_average_attempts(target), max_att)
    other_weights, other_total_weight, other_donation_weight = tracker.get_cumulative_weights(
        previous_share_hash, min(height, chain_length),
        65535 * max(0, max_att - this_att))
    assert other_total_weight == sum(
        other_weights.itervalues()) + other_donation_weight, (
            other_total_weight,
            sum(other_weights.itervalues()) + other_donation_weight)
    weights, total_weight, donation_weight = math.add_dicts(
        [{
            new_script: this_att * (65535 - donation)
        }, other_weights]
    ), this_att * 65535 + other_total_weight, this_att * donation + other_donation_weight
    assert total_weight == sum(weights.itervalues()) + donation_weight, (
        total_weight, sum(weights.itervalues()) + donation_weight)

    SCRIPT = '4104ffd03de44a6e11b9917f3a29f9443283d9871c9d743ef30d5eddcd37094b64d1b3d8090496b53256786bf5c82932ec23c3b74d9f05a6f95a8b5529352656664bac'.decode(
        'hex')

    # 1 satoshi is always donated so that a list of p2pool generated blocks can be easily found by looking at the donation address
    amounts = dict(
        (script, (subsidy - 1) * (199 * weight) // (200 * total_weight))
        for (script, weight) in weights.iteritems())
    amounts[new_script] = amounts.get(new_script, 0) + (subsidy - 1) // 200
    amounts[SCRIPT] = amounts.get(
        SCRIPT,
        0) + (subsidy - 1) * (199 * donation_weight) // (200 * total_weight)
    amounts[SCRIPT] = amounts.get(SCRIPT, 0) + subsidy - sum(
        amounts.itervalues())  # collect any extra satoshis :P

    if sum(amounts.itervalues()) != subsidy:
        raise ValueError()
    if any(x < 0 for x in amounts.itervalues()):
        raise ValueError()

    dests = sorted(amounts.iterkeys(),
                   key=lambda script: (amounts[script], script))
    dests = dests[-4000:]  # block length limit, unlikely to ever be hit

    share_info = dict(
        share_data=share_data,
        target=target,
        timestamp=math.clip(desired_timestamp, (previous_share.timestamp - 60,
                                                previous_share.timestamp + 60))
        if previous_share is not None else desired_timestamp,
    )

    return share_info, dict(
        version=1,
        tx_ins=[
            dict(
                previous_output=None,
                sequence=None,
                script=share_data['coinbase'].ljust(2, '\x00'),
            )
        ],
        tx_outs=[
            dict(value=0,
                 script='\x20' + bitcoin_data.HashType().pack(
                     share_info_type.hash256(share_info)))
        ] + [
            dict(value=amounts[script], script=script)
            for script in dests if amounts[script]
        ],
        lock_time=0,
    )