Example #1
0
def create_mining_block(consensus):
    global mining_address
    # create proof_tx
    mining_address = mining_address or V.MINING_ADDRESS or new_key()
    reward = GompertzCurve.calc_block_reward(previous_block.height + 1)
    fees = sum(tx.gas_amount * tx.gas_price for tx in unconfirmed_txs)
    proof_tx = TX(
        tx={
            'type': C.TX_POW_REWARD,
            'inputs': list(),
            'outputs': [(mining_address, 0, reward + fees)],
            'gas_price': 0,
            'gas_amount': 0,
            'message_type': C.MSG_PLAIN if V.MINING_MESSAGE else C.MSG_NONE,
            'message': V.MINING_MESSAGE if V.MINING_MESSAGE else b''
        })
    proof_tx.update_time()
    # create mining block
    bits, target = get_bits_by_hash(previous_hash=previous_block.hash,
                                    consensus=consensus)
    mining_block = Block(
        block={
            'merkleroot': b'\xff' * 32,
            'time': 0,
            'previous_hash': previous_block.hash,
            'bits': bits,
            'nonce': b'\xff\xff\xff\xff'
        })
    proof_tx.height = previous_block.height + 1
    mining_block.height = proof_tx.height
    mining_block.flag = consensus
    mining_block.bits2target()
    mining_block.txs.append(proof_tx)
    mining_block.txs.extend(unconfirmed_txs)
    mining_block.update_merkleroot()
    mining_block.update_time(proof_tx.time)
    return mining_block
Example #2
0
 def proof_of_stake(self):
     global staking_limit
     limit_deque = deque(maxlen=10)
     self.event_close.set()
     while self.event_close.is_set():
         # check start mining
         if previous_block is None or unconfirmed_txs is None or unspents_txs is None:
             sleep(0.1)
             continue
         if len(unspents_txs) == 0:
             logging.info("No unspents for staking, wait 180s..")
             sleep(180)
             continue
         start = time()
         # create staking block
         bits, target = get_bits_by_hash(previous_hash=previous_block.hash,
                                         consensus=C.BLOCK_POS)
         reward = GompertzCurve.calc_block_reward(previous_block.height + 1)
         staking_block = Block(
             block={
                 'merkleroot': b'\xff' * 32,
                 'time': 0,
                 'previous_hash': previous_block.hash,
                 'bits': bits,
                 'nonce': b'\xff\xff\xff\xff'
             })
         staking_block.height = previous_block.height + 1
         staking_block.flag = C.BLOCK_POS
         staking_block.bits2target()
         staking_block.txs.append(None)  # Dummy proof tx
         staking_block.txs.extend(unconfirmed_txs)
         calculate_nam = 0
         for proof_tx in unspents_txs.copy():
             address = proof_tx.outputs[0][0]
             proof_tx.outputs[0] = (address, 0,
                                    proof_tx.pos_amount + reward)
             proof_tx.update_time()
             calculate_nam += 1
             # next check block
             if previous_block is None or unconfirmed_txs is None or unspents_txs is None:
                 logging.debug("Reset by \"nothing params found\"")
                 sleep(1)
                 break
             elif previous_block.hash != staking_block.previous_hash:
                 logging.debug("Reset by \"Don't match previous_hash\"")
                 sleep(1)
                 break
             elif not proof_tx.pos_check(
                     previous_hash=previous_block.hash,
                     pos_target_hash=staking_block.target_hash):
                 continue
             else:
                 # Staked yay!!
                 proof_tx.height = staking_block.height
                 proof_tx.signature = [
                     message2signature(proof_tx.b, proof_tx.outputs[0][0])
                 ]
                 staking_block.txs[0] = proof_tx
                 # Fit block size
                 while staking_block.getsize() > C.SIZE_BLOCK_LIMIT:
                     tx = staking_block.txs.pop()
                     if tx.type == C.TX_FINISH_CONTRACT:
                         staking_block.txs.pop()
                 staking_block.update_time(proof_tx.time)
                 staking_block.update_merkleroot()
                 confirmed_generating_block(staking_block)
                 break
         else:
             # check time
             used = time() - start
             remain = 1.0 - used
             max_limit = max(50, int(calculate_nam / max(0.0001, used)))
             limit_deque.append(int(max_limit * self.power_limit))
             staking_limit = sum(limit_deque) // len(limit_deque)
             if int(time()) % 90 == 0:
                 logging.info("Staking... margin={}% limit={}".format(
                     round(remain * 100, 1), staking_limit))
             self.hashrate = (calculate_nam, time())
             sleep(max(0.0, remain))
     logging.info("Close signal")
Example #3
0
def create_genesis_block(all_supply,
                         block_span,
                         prefix=b'\x98',
                         contract_prefix=b'\x12',
                         digit_number=8,
                         minimum_price=100,
                         consensus=None,
                         premine=None):
    """
    Height0のGenesisBlockを作成する
    :param all_supply: PoW/POS合わせた全採掘量、プリマインを除く
    :param block_span: Blockの採掘間隔(Sec)
    :param prefix: 一般アドレスの頭文字、b'\x98'=N
    :param contract_prefix: コントラクトの頭文字、b'\x98'=C
    :param digit_number: コインの分解能
    :param minimum_price: 最小gas_price
    :param consensus: 採掘アルゴ {consensus: ratio(0~100), ..}
    :param premine: プリマイン [(address, coin_id, amount), ...]
    """

    # default: Yescript9割, Stake1割の分配
    consensus = consensus or {C.BLOCK_YES_POW: 90, C.BLOCK_POS: 10}
    if sum(consensus.values()) != 100:
        raise BlockChainError('sum of consensus values is 100 [!={}]'.format(
            sum(consensus.values())))
    elif not isinstance(sum(consensus.values()), int):
        raise BlockChainError('value is int only.')
    elif not (0 < min(consensus.values()) <= 100):
        raise BlockChainError('out of range {}'.format(min(
            consensus.values())))
    elif not (0 < max(consensus.values()) <= 100):
        raise BlockChainError('out of range {}'.format(min(
            consensus.values())))
    all_consensus = {
        C.BLOCK_POS, C.BLOCK_YES_POW, C.BLOCK_X11_POW, C.BLOCK_HMQ_POW,
        C.BLOCK_LTC_POW, C.BLOCK_X16_POW
    }
    if len(set(consensus.keys()) - all_consensus) > 0:
        raise BlockChainError('Not found all_consensus number {}'.format(
            set(consensus.keys()) - all_consensus))
    elif len(set(consensus.keys()) & all_consensus) == 0:
        raise BlockChainError('No usable consensus found {}'.format(
            set(consensus.keys()) & all_consensus))

    # params
    assert isinstance(minimum_price, int), 'minimum_price is INT'
    genesis_time = int(time.time())
    # premine
    premine_txs = list()
    for index, chunk in enumerate(chunked(premine or list(), 256)):
        tx = TX(
            tx={
                'version': __chain_version__,
                'type': C.TX_TRANSFER,
                'time': 0,
                'deadline': 10800,
                'inputs': list(),
                'outputs': chunk,
                'gas_price': 0,
                'gas_amount': 0,
                'message_type': C.MSG_PLAIN,
                'message': 'Premine {}'.format(index).encode()
            })
        tx.height = 0
        premine_txs.append(tx)
    # validator
    V.BLOCK_GENESIS_TIME = int(time.time())
    with closing(create_db(V.DB_ACCOUNT_PATH)) as db:
        ck = create_new_user_keypair(C.ANT_CONTRACT, db.cursor())
        db.commit()
    c_address = convert_address(ck, contract_prefix)
    c_bin = contract2binary(Contract)
    c_cs = {
        ck.encode(): b'\x00\x00\x00\x00',
        b'\x00' + b'\x00\x00\x00\x00': b'\x01'
    }  # TODO: 初期値どうする?
    validator_tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_CREATE_CONTRACT,
            'time': 0,
            'deadline': 10800,
            'inputs': list(),
            'outputs': list(),
            'gas_price': 0,
            'gas_amount': 0,
            'message_type': C.MSG_BYTE,
            'message': bjson.dumps((c_address, c_bin, c_cs), compress=False)
        })
    validator_tx.height = 0
    params = {
        'prefix': prefix,  # CompressedKey prefix
        'contract_prefix': contract_prefix,  # ContractKey prefix
        'validator_address': c_address,
        'genesis_time': genesis_time,  # GenesisBlockの採掘時間
        'all_supply': all_supply,  # 全採掘量
        'block_span': block_span,  # ブロックの採掘間隔
        'digit_number': digit_number,  # 小数点以下の桁数
        'minimum_price': minimum_price,
        'contract_minimum_amount': pow(10, digit_number),
        'consensus': consensus
    }  # Block承認のアルゴリズム
    # BLockChainの設定TX
    setting_tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_GENESIS,
            'time': 0,
            'deadline': 10800,
            'inputs': list(),
            'outputs': list(),
            'gas_price': 0,
            'gas_amount': 0,
            'message_type': C.MSG_BYTE,
            'message': bjson.dumps(params, compress=False)
        })
    setting_tx.height = 0
    # height0のBlock生成
    genesis_block = Block(
        block={
            'merkleroot': b'\x00' * 32,
            'time': 0,
            'previous_hash': b'\xff' * 32,
            'bits': MAX_BITS,
            'nonce': b'\xff' * 4
        })
    # block params
    genesis_block.height = 0
    genesis_block.flag = C.BLOCK_GENESIS
    # block body
    genesis_block.txs.append(setting_tx)
    genesis_block.txs.append(validator_tx)
    genesis_block.txs.extend(premine_txs)
    genesis_block.bits2target()
    genesis_block.target2diff()
    genesis_block.update_merkleroot()
    genesis_block.serialize()
    return genesis_block