Пример #1
0
def finish_contract_tx(start_tx, f_limit=True):
    assert start_tx.height is None, 'StartTX height is None.'
    assert P.VALIDATOR_OBJ, 'You are not a validator.'
    c_address, c_data, c_args, c_redeem = bjson.loads(start_tx.message)
    if f_limit:
        gas_limit = start_tx.gas_amount - start_tx.getsize()
    else:
        gas_limit = None
    status, result, estimate_gas, line = try_emulate(start_tx, gas_limit)
    if status:
        # 成功時
        outputs, cs_result = result
        if cs_result is None:
            message = bjson.dumps((True, start_tx.hash, None), compress=False)
        else:
            cs = get_contract_storage(c_address)
            cs_diff = cs.diff_dev(new_key_value=cs_result.key_value)
            message = bjson.dumps((True, start_tx.hash, cs_diff),
                                  compress=False)
        try:
            check_output_format(outputs)
        except BlockChainError as e:
            logging.debug("Contract failed `emulate success` {}".format(e))
            return failed_finish_tx(start_tx), estimate_gas

    else:
        # 失敗時
        outputs = None
        logging.debug("Contract failed `emulate failed` {}".format(result))
        return failed_finish_tx(start_tx), 0
    # finish tx 作成
    finish_tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_FINISH_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'inputs': list(),
            'outputs': outputs or list(),
            'gas_price': start_tx.gas_price,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': message
        })
    to_user_redeem = (c_redeem, 0, 0)
    finish_tx.outputs.append(to_user_redeem)  # gas_amountを返す
    # fill input/output
    # TODO: c_redeemを用いてFeeを還元
    redeem_gas = start_tx.gas_amount - start_tx.getsize() - estimate_gas
    if not fill_inputs_outputs(finish_tx, c_address, start_tx.hash,
                               redeem_gas):
        return failed_finish_tx(start_tx), estimate_gas
    redeem_idx = finish_tx.outputs.index(to_user_redeem)
    redeem_amount = -1 * finish_tx.gas_amount * finish_tx.gas_price
    finish_tx.outputs[redeem_idx] = (c_redeem, 0, redeem_amount)
    replace_redeem_dummy_address(finish_tx, c_address)
    finish_tx.serialize()
    return finish_tx, estimate_gas
Пример #2
0
def create_contract_transfer_tx(c_address,
                                cur,
                                c_method,
                                c_args=None,
                                send_pairs=None,
                                sender=C.ANT_UNKNOWN,
                                gas_price=None,
                                retention=10800):
    assert isinstance(c_method, str)
    if sender in (C.ANT_OUTSIDE, C.ANT_RESERVED):
        raise BlockChainError('Not allowed inner account.')
    if c_args is None:
        c_args = tuple()
    else:
        c_args = tuple(c_args)
    redeem_address = create_new_user_keypair(read_user2name(sender, cur), cur)
    msg_body = bjson.dumps((c_address, c_method, redeem_address, c_args),
                           compress=False)
    send_pairs = send_pairs_format_check(c_address=c_address,
                                         send_pairs=send_pairs)
    tx = send_many(sender=sender,
                   send_pairs=send_pairs,
                   cur=cur,
                   fee_coin_id=0,
                   gas_price=gas_price,
                   msg_type=C.MSG_BYTE,
                   msg_body=msg_body,
                   retention=retention)
    return tx
Пример #3
0
def create_conclude_tx(c_address, start_tx, send_pairs=None, c_storage=None):
    assert isinstance(start_tx, TX)
    assert send_pairs is None or isinstance(send_pairs, list)
    assert c_storage is None or isinstance(c_storage, dict)
    message = bjson.dumps((c_address, start_tx.hash, c_storage),
                          compress=False)
    v = get_validator_object(c_address=c_address)
    send_pairs = send_pairs or list()
    tx = TX(
        tx={
            'type': C.TX_CONCLUDE_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'gas_price': start_tx.gas_price,
            'gas_amount': 0,
            'outputs': [tuple(s) for s in send_pairs],
            'message_type': C.MSG_BYTE,
            'message': message
        })
    extra_gas = C.SIGNATURE_GAS * v.require
    tx.gas_amount = tx.size + extra_gas
    # fill unspents
    fill_contract_inputs_outputs(tx=tx,
                                 c_address=c_address,
                                 additional_gas=extra_gas)
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, replace_by=c_address)
    tx.serialize()
    if v.index == -1:
        raise BlockChainError(
            'Not init validator address. {}'.format(c_address))
    if setup_contract_signature(tx, v.validators) == 0:
        raise BlockChainError('Cannot sign, you are not validator.')
    return tx
Пример #4
0
def test():
    import time
    import json
    with open("sample.json") as f:
        t = json.load(f)
    t.append("namuyan" * 1024)
    s = time.time()

    pr_dump = cProfile.Profile()
    pr_dump.enable()
    bj = dumps(t)
    pr_dump.disable()
    print("encode", time.time() - s, "Sec")
    stats_dump = pstats.Stats(pr_dump)
    stats_dump.sort_stats('ncalls')
    stats_dump.print_stats()

    pr_load = cProfile.Profile()
    pr_load.enable()
    decoded = loads(bj)
    pr_load.disable()
    print("decode", time.time() - s, "Sec")
    stats_load = pstats.Stats(pr_load)
    stats_load.sort_stats('ncalls')
    stats_load.print_stats()

    print(len(bj) // 1000, "kB, match=", t == decoded)
Пример #5
0
def create_contract_update_tx(c_address,
                              cur,
                              c_bin=None,
                              c_extra_imports=None,
                              c_settings=None,
                              send_pairs=None,
                              sender=C.ANT_UNKNOWN,
                              gas_price=None,
                              retention=10800):
    assert c_bin or c_extra_imports or c_settings
    if sender in (C.ANT_OUTSIDE, C.ANT_RESERVED):
        raise BlockChainError('Not allowed inner account.')
    c_method = contract.M_UPDATE
    c_args = (c_bin, c_extra_imports, c_settings)
    redeem_address = create_new_user_keypair(read_user2name(sender, cur), cur)
    msg_body = bjson.dumps((c_address, c_method, redeem_address, c_args),
                           compress=False)
    send_pairs = send_pairs_format_check(c_address=c_address,
                                         send_pairs=send_pairs)
    tx = send_many(sender=sender,
                   send_pairs=send_pairs,
                   cur=cur,
                   fee_coin_id=0,
                   gas_price=gas_price,
                   msg_type=C.MSG_BYTE,
                   msg_body=msg_body,
                   retention=retention)
    return tx
Пример #6
0
 def write_coins(self, coin_id, txhash, params, setting):
     assert self.is_batch_thread(), 'Not created batch.'
     index = -1
     for index, *dummy in self.read_coins_iter(coin_id=coin_id): pass
     index += 1
     k = coin_id.to_bytes(4, ITER_ORDER) + index.to_bytes(4, ITER_ORDER)
     v = txhash + bjson.dumps((params, setting), compress=False)
     self.batch['_coins'][k] = v
     logging.debug("Insert new coins id={}".format(coin_id))
Пример #7
0
 def write_contract(self, c_address, start_hash, finish_hash, message):
     assert self.is_batch_thread(), 'Not created batch.'
     assert len(message) == 3
     index = -1
     for index, *dummy in self.read_contract_iter(c_address=c_address): pass
     index += 1
     k = c_address.encode() + index.to_bytes(4, ITER_ORDER)
     v = start_hash + finish_hash + bjson.dumps(message, compress=False)
     self.batch['_contract'][k] = v
     logging.debug("Insert new contract {} {}".format(c_address, index))
Пример #8
0
 def create_cert(master_sk, signer_pk, cert_start, cert_stop):
     assert int(time.time()) < cert_start < cert_stop, 'wrong time setting of cert.'
     master_ecc = Encryption()
     master_ecc.sk = master_sk
     cert_raw = bjson.dumps((master_ecc.pk, signer_pk, cert_start, cert_stop), compress=False)
     cert = {
         'master': master_ecc.pk,
         'start': cert_start,
         'stop': cert_stop,
         'sign': master_ecc.sign(cert_raw, encode='hex')}
     return cert
Пример #9
0
def create_contract_tx(c_bin,
                       cur,
                       sender=C.ANT_UNKNOWN,
                       c_cs=None,
                       gas_price=None,
                       retention=10800):
    assert isinstance(c_bin, bytes), 'contract is bytes code.'
    assert isinstance(sender, int), 'Sender is id.'
    if c_cs:
        for k, v in c_cs.items():
            assert isinstance(k, bytes), 'Key is bytes.'
            assert isinstance(v, bytes), 'Value is bytes.'
    # TXを作成
    now = int(time.time()) - V.BLOCK_GENESIS_TIME
    ck = create_new_user_keypair(C.ANT_NAME_CONTRACT, cur)
    c_address = convert_address(ck, V.BLOCK_CONTRACT_PREFIX)
    message = bjson.dumps((c_address, c_bin, c_cs), compress=False)
    tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_CREATE_CONTRACT,
            'time': now,
            'deadline': now + retention,
            'inputs': list(),
            'outputs': list(),
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': message
        })
    tx.gas_amount = tx.getsize() + C.CONTRACT_CREATE_FEE + 96
    # fill unspents
    fee_coin_id = 0
    input_address = fill_inputs_outputs(tx, cur, fee_coin_id,
                                        C.CONTRACT_CREATE_FEE)
    fee_coins = CoinObject(fee_coin_id, tx.gas_price * tx.gas_amount)
    movements = UserCoins()
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    # account check
    send_coins = CoinObject()
    check_enough_amount(sender, send_coins, fee_coins)
    if sender in (C.ANT_OUTSIDE, C.ANT_RESERVED):
        raise BlockChainError('Not allowed inner account.')
    # replace dummy address
    replace_redeem_dummy_address(tx, cur)
    # setup signature
    tx.serialize()
    setup_signature(tx, input_address)
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    insert_log(movements, cur, tx.type, tx.time, tx.hash)
    return c_address, tx
Пример #10
0
def start_contract_tx(c_address,
                      c_method,
                      cur,
                      c_args=None,
                      outputs=None,
                      sender=C.ANT_UNKNOWN,
                      gas_price=None,
                      additional_gas_amount=None,
                      retention=10800):
    # TXを作成
    now = int(time.time()) - V.BLOCK_GENESIS_TIME
    c_redeem = create_new_user_keypair(C.ANT_NAME_UNKNOWN, cur)
    message = bjson.dumps((c_address, c_method, c_args or tuple(), c_redeem),
                          compress=False)
    tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_START_CONTRACT,
            'time': now,
            'deadline': now + retention,
            'inputs': list(),
            'outputs': outputs or list(),
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': message
        })
    check_output_format(tx.outputs)
    tx.gas_amount = tx.getsize() + 96
    tx.serialize()
    # fill unspents
    fee_coin_id = 0
    input_address = fill_inputs_outputs(
        tx, cur, fee_coin_id, additional_gas_amount
        or V.CONTRACT_MINIMUM_AMOUNT)
    fee_coins = CoinObject(fee_coin_id, tx.gas_price * tx.gas_amount)
    movements = UserCoins()
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    # account check
    send_coins = CoinObject()
    check_enough_amount(sender, send_coins, fee_coins)
    if sender in (C.ANT_OUTSIDE, C.ANT_RESERVED):
        raise BlockChainError('Not allowed inner account.')
    # replace dummy address
    replace_redeem_dummy_address(tx, cur)
    # setup signature
    tx.serialize()
    setup_signature(tx, input_address)
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    insert_log(movements, cur, tx.type, tx.time, tx.hash)
    return tx
Пример #11
0
 def generate_sign(self, sk):
     assert self.version is not None, 'mint version error.'
     d = {
         'version': self.version,
         'coin_id': self.coin_id,
         'name': self.name,
         'unit': self.unit,
         'digit': self.digit,
         'amount': self.amount,
         'additional_issue': self.additional_issue,
         'owner': self.owner
     }
     binary = bjson.dumps(d, compress=False)
     self.sign = sign(msg=binary, sk=sk, pk=self.owner)
Пример #12
0
 def write_contract(self, c_address, start_tx, finish_hash, message):
     assert self.is_batch_thread(), 'Not created batch.'
     assert len(message) == 3
     include_block = self.read_block(blockhash=self.read_block_hash(height=start_tx.height))
     index = start_tx.height * 0xffffffff + include_block.txs.index(start_tx)
     # check newer index already inserted
     last_index = None
     for last_index, *dummy in self.read_contract_iter(c_address=c_address, start_idx=index):
         pass
     assert last_index is None, 'Not allow older ConcludeTX insert. my={} last={}'.format(index, last_index)
     k = c_address.encode() + index.to_bytes(8, ITER_ORDER)
     v = start_tx.hash + finish_hash + bjson.dumps(message, compress=False)
     self.batch['_contract'][k] = v
     logging.debug("Insert new contract {} {}".format(c_address, index))
Пример #13
0
def create_validator_edit_tx(c_address,
                             new_address=None,
                             flag=F_NOP,
                             sig_diff=0,
                             gas_price=None,
                             retention=10800):
    assert not (flag == F_NOP and sig_diff == 0), 'No edit info.'
    if new_address is None and flag != F_NOP:
        raise BlockChainError('No cosigner edit, but flag is not NOP.')
    # validator object
    v = get_validator_object(c_address=c_address)
    if v.version == -1:
        if new_address is None or flag != F_ADD or sig_diff != 1:
            raise BlockChainError('Not correct info.')
    else:
        next_require = v.require + sig_diff
        next_validator_num = len(v.validators)
        if flag == F_ADD:
            next_validator_num += 1
        elif flag == F_REMOVE:
            next_validator_num -= 1
        if not (0 < next_require <= next_validator_num):
            raise BlockChainError('ReqError, 0 < {} <= {}'.format(
                next_require, next_validator_num))
    # tx create
    message = bjson.dumps((c_address, new_address, flag, sig_diff),
                          compress=False)
    tx = TX(
        tx={
            'type': C.TX_VALIDATOR_EDIT,
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 0,
            'message_type': C.MSG_BYTE,
            'message': message
        })
    extra_gas = C.VALIDATOR_EDIT_GAS + C.SIGNATURE_GAS * v.require
    tx.gas_amount = tx.size + extra_gas
    tx.update_time(retention)
    # fill unspents
    fill_contract_inputs_outputs(tx=tx,
                                 c_address=c_address,
                                 additional_gas=extra_gas)
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, replace_by=c_address)
    tx.serialize()
    if len(v.validators) > 0 and setup_contract_signature(tx,
                                                          v.validators) == 0:
        raise BlockChainError('Cannot sign, you are not validator.')
    return tx
Пример #14
0
def failed_finish_tx(start_tx):
    message = bjson.dumps((False, start_tx.hash, None), compress=False)
    return TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_FINISH_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'inputs': list(),
            'outputs': list(),
            'gas_price': start_tx.gas_price,
            'gas_amount': 0,
            'message_type': C.MSG_BYTE,
            'message': message
        })
Пример #15
0
    def _send_msg(self, item, allows=None, denys=None):
        msg_body = bjson.dumps(item)
        if allows is None:
            allows = self.p2p.user
        if denys is None:
            denys = list()

        c = 0
        for user in allows:
            if user not in denys:
                try:
                    self.p2p.send_msg_body(msg_body=msg_body, user=user)
                except Exception as e:
                    logging.debug("Failed send msg to {}, {}".format(user.name, e))
                c += 1
        return c  # 送った送信先
Пример #16
0
 def check_sign(self):
     d = {
         'version': self.version,
         'coin_id': self.coin_id,
         'name': self.name,
         'unit': self.unit,
         'digit': self.digit,
         'amount': self.amount,
         'additional_issue': self.additional_issue,
         'owner': self.owner
     }
     binary = bjson.dumps(d, compress=False)
     try:
         verify(msg=binary, sign=self.sign, pk=self.owner)
     except ValueError:
         raise MintCoinError('signature verification failed.')
Пример #17
0
 def serialize(self):
     d = {
         'version': self.version,
         'coin_id': self.coin_id,
         'amount': self.amount,
         'owner': self.owner,
         'sign': self.sign
     }
     if self.name is not None: d['name'] = self.name
     if self.unit is not None: d['unit'] = self.unit
     if self.digit is not None: d['digit'] = self.digit
     if self.additional_issue is not None:
         d['additional_issue'] = self.additional_issue
     if self.image is not None: d['image'] = self.image
     if self.message is not None: d['message'] = self.message
     self.binary = bjson.dumps(d, compress=False)
Пример #18
0
def create_boot_file(genesis_block, network_ver=None, connections=None):
    network_ver = network_ver or random.randint(1000000, 0xffffffff)
    assert isinstance(network_ver, int) and abs(
        network_ver) <= 0xffffffff, 'network_ver is int <=0xffffffff.'
    data = {
        'block': genesis_block.b,
        'txs': [tx.b for tx in genesis_block.txs],
        'connections': connections or list(),
        'network_ver': network_ver
    }
    boot_path = os.path.join(V.DB_HOME_DIR, 'boot.dat')
    data = b64encode(bjson.dumps(data))
    with open(boot_path, mode='bw') as fp:
        while len(data) > 0:
            write, data = data[:60], data[60:]
            fp.write(write + b'\n')
    logging.info("create new boot.dat!")
Пример #19
0
 def remove_file_by_master(self, signer_sk, cert, file_hash):
     file_hash = file_hash.lower()
     file_path = os.path.join(V.DATA_PATH, 'file.' + file_hash + '.dat')
     uuid = random.randint(10, 99999999)
     signer_ecc = Encryption()
     signer_ecc.sk = signer_sk
     try:
         os.remove(file_path)
         sign_raw = bjson.dumps((file_hash, uuid), compress=False)
         send_data = {
             'signer': signer_ecc.pk,
             'sign': signer_ecc.sign(msg=sign_raw, encode='hex'),
             'cert': cert}
         dummy, result = self.send_command(ClientCmd.FILE_DELETE, send_data, uuid=uuid)
         logging.debug("File delete success.")
     except:
         logging.debug("Failed delete file.")
         pass
Пример #20
0
    def send_msg_body(self,
                      msg_body,
                      user=None,
                      status=200,
                      f_udp=False,
                      f_pro_force=False):
        # StatusCode: https://ja.wikipedia.org/wiki/HTTPステータスコード
        assert type(msg_body) == bytes, 'msg_body is bytes'
        assert 200 <= status < 600, 'Not found status code {}'.format(status)

        # get client
        if len(self.user) == 0:
            raise ConnectionError('client connection is zero.')
        elif len(msg_body) > C.MAX_RECEIVE_SIZE + 5000:
            error = 'Max message size is {}kb (You try {}Kb)'.format(
                round(C.MAX_RECEIVE_SIZE / 1000000, 3),
                round(len(msg_body) / 1000000, 3))
            self.send_msg_body(msg_body=bjson.dumps(error),
                               user=user,
                               status=500)
            raise ConnectionRefusedError(error)
        elif user is None:
            user = random.choice(self.user)

        # send message
        if f_udp and f_pro_force:
            self._udp_body(msg_body, user)
        elif f_udp and user.p2p_udp_accept and len(msg_body) < 1400:
            self._udp_body(msg_body, user)
        else:
            msg_body = zlib.compress(msg_body)
            msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body)
            msg_len = len(msg_body).to_bytes(4, 'big')
            send_data = msg_len + msg_body
            user.send(send_data)
            self.traffic.put_traffic_up(send_data)
        # logging.debug("Send {}Kb to '{}'".format(len(msg_len+msg_body) / 1000, user.name))
        return user
Пример #21
0
def issue_mintcoin(name,
                   unit,
                   digit,
                   amount,
                   cur,
                   description=None,
                   image=None,
                   additional_issue=True,
                   change_address=True,
                   gas_price=None,
                   sender=C.ANT_UNKNOWN,
                   retention=10800):
    mint_id = get_new_coin_id()
    sender_name = read_user2name(user=sender, cur=cur)
    mint_address = create_new_user_keypair(name=sender_name, cur=cur)
    params = {
        "name": name,
        "unit": unit,
        "digit": digit,
        "address": mint_address,
        "description": description,
        "image": image
    }
    setting = {
        "additional_issue": additional_issue,
        "change_address": change_address
    }
    m_before = get_mintcoin_object(coin_id=mint_id)
    result = check_mintcoin_new_format(m_before=m_before,
                                       new_params=params,
                                       new_setting=setting)
    if isinstance(result, str):
        raise BlockChainError('check_mintcoin_new_format(): {}'.format(result))
    msg_body = bjson.dumps((mint_id, params, setting), compress=False)
    tx = TX(
        tx={
            'type': C.TX_MINT_COIN,
            'inputs': list(),
            'outputs': [(MINTCOIN_DUMMY_ADDRESS, 0, amount)],
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': msg_body
        })
    tx.update_time(retention)
    additional_gas = C.MINTCOIN_GAS
    tx.gas_amount = tx.size + C.SIGNATURE_GAS + additional_gas
    tx.serialize()
    # fill unspents
    fee_coin_id = 0
    input_address = fill_inputs_outputs(tx=tx,
                                        cur=cur,
                                        fee_coin_id=fee_coin_id,
                                        additional_gas=additional_gas)
    # input_address.add(mint_address)
    fee_coins = Balance(coin_id=fee_coin_id,
                        amount=tx.gas_price * tx.gas_amount)
    # check amount
    check_enough_amount(sender=sender,
                        send_coins=Balance(0, amount),
                        fee_coins=fee_coins)
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, cur=cur)
    # replace dummy mint_id
    replace_mint_dummy_address(tx=tx,
                               mint_address=mint_address,
                               mint_id=mint_id,
                               f_raise=True)
    # setup signature
    tx.serialize()
    setup_signature(tx=tx, input_address=input_address)
    # movement
    movements = Accounting()
    minting_coins = Balance(mint_id, amount)
    movements[sender] += minting_coins
    movements[C.ANT_OUTSIDE] -= minting_coins
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    insert_log(movements, cur, tx.type, tx.time, tx.hash)
    return mint_id, tx
Пример #22
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
Пример #23
0
def create_conclude_tx(c_address,
                       start_tx,
                       redeem_address,
                       send_pairs=None,
                       c_storage=None,
                       emulate_gas=0):
    assert isinstance(start_tx, TX)
    assert send_pairs is None or isinstance(send_pairs, list)
    assert c_storage is None or isinstance(c_storage, dict)
    assert isinstance(emulate_gas, int)
    message = bjson.dumps((c_address, start_tx.hash, c_storage),
                          compress=False)
    v = get_validator_object(c_address=c_address)
    send_pairs = send_pairs or list()
    tx = TX(
        tx={
            'type': C.TX_CONCLUDE_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'gas_price': start_tx.gas_price,
            'gas_amount': 0,
            'outputs': [tuple(s) for s in send_pairs],
            'message_type': C.MSG_BYTE,
            'message': message
        })
    extra_gas = C.SIGNATURE_GAS * v.require
    tx.gas_amount = tx.size + extra_gas
    # fill unspents
    fill_contract_inputs_outputs(tx=tx,
                                 c_address=c_address,
                                 additional_gas=extra_gas)
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, replace_by=c_address)
    # fix redeem fees
    if send_pairs:
        # conclude_txで使用したGasを、ユーザーから引いてコントラクトに戻す処理
        conclude_fee = (emulate_gas + tx.gas_amount) * tx.gas_price
        fee_coin_id = 0
        f_finish_add = f_finish_sub = False
        for index, (address, coin_id, amount) in enumerate(tx.outputs):
            if coin_id != fee_coin_id:
                continue
            elif not f_finish_add and address == c_address:
                f_finish_add = True
                tx.outputs[index] = (address, coin_id, amount + conclude_fee)
            elif not f_finish_sub and address == redeem_address:
                f_finish_sub = True
                tx.outputs[index] = (address, coin_id, amount - conclude_fee)
            else:
                pass
        if not (f_finish_add and f_finish_sub):
            raise BlockChainError(
                'Cannot move conclude fee, add={} sub={}'.format(
                    f_finish_add, f_finish_sub))
        logging.debug("Move conclude fee {}:{}".format(fee_coin_id,
                                                       conclude_fee))
    tx.serialize()
    if v.version == -1:
        raise BlockChainError(
            'Not init validator address. {}'.format(c_address))
    if setup_contract_signature(tx, v.validators) == 0:
        raise BlockChainError('Cannot sign, you are not validator.')
    return tx
Пример #24
0
def obj2bjson(o):
    return bjson.dumps(o)
Пример #25
0
    def type_request(self, user, item):
        temperate = {
            'type': T_RESPONSE,
            'cmd': item['cmd'],
            'data': None,
            'time': time.time(),
            'uuid': item['uuid']}
        allow_list = list()
        deny_list = list()
        ack_list = list()

        if item['cmd'] == ClientCmd.PING_PONG:
            temperate['data'] = {
                'ping': item['data'],
                'pong': time.time()}
            allow_list.append(user)

        elif item['cmd'] == ClientCmd.BROADCAST:
            if item['uuid'] in self.__broadcast_uuid:
                return  # already get broadcast data
            elif self.__waiting_result.include(item['uuid']):
                return  # I'm broadcaster, get from ack
            elif not self.broadcast_check(item['data']):
                user.warn += 1
                self.__broadcast_uuid.append(item['uuid'])
                return  # not allowed broadcast data
            else:
                self.__broadcast_uuid.append(item['uuid'])
                self.broadcast_que.broadcast(item['data'])
                deny_list.append(user)
                allow_list = None
                # send ACK
                ack_list.append(user)
                # send Response
                temperate['type'] = T_REQUEST
                temperate['data'] = item['data']

        elif item['cmd'] == ClientCmd.GET_PEER_INFO:
            # [[(host,port), header],..]
            temperate['data'] = self.peers.data
            allow_list.append(user)

        elif item['cmd'] == ClientCmd.GET_NEARS:
            temperate['data'] = {user.get_host_port(): user.serialize() for user in self.p2p.user}
            allow_list.append(user)

        elif item['cmd'] == ClientCmd.CHECK_REACHABLE:
            try:
                port = item['data']['port']
            except:
                port = user.p2p_port
            temperate['data'] = is_reachable(host=user.host_port[0], port=port)
            allow_list.append(user)

        elif item['cmd'] == ClientCmd.FILE_CHECK:
            # {'hash': hash, 'uuid': uuid}
            file_hash = item['data']['hash']
            file_path = os.path.join(V.TMP_PATH, 'file.' + file_hash + '.dat')
            f_existence = os.path.exists(file_path)
            if 'uuid' in item['data']:
                f_asked = self.__user2user_route.include(item['data']['uuid'])
            else:
                f_asked = False
            temperate['data'] = {'have': f_existence, 'asked': f_asked}
            allow_list.append(user)

        elif item['cmd'] == ClientCmd.FILE_GET:
            def asking():
                # ファイル要求元のNodeに近いNode群を無視する
                nears_name = set(user_.name for user_ in self.p2p.user)
                best_name = list(nears_name - already_asked_user)
                random.shuffle(best_name)
                nears_name = list(nears_name)
                random.shuffle(nears_name)
                # nearを最後に探索するように並び替え
                try_to_ask_name = best_name + nears_name

                # ファイル所持Nodeを見つけたら即コマンド送る、それ以外は候補をリスト化
                candidates = list()
                for ask_name in try_to_ask_name:
                    try:
                        ask_user = self.p2p.name2user(ask_name)
                        if ask_user is None:
                            continue
                        send_data = {'hash': file_hash, 'uuid': item['uuid']}
                        dummy, data = self.send_command(cmd=ClientCmd.FILE_CHECK, user=ask_user,
                                                        data=send_data, timeout=2)
                    except Exception as e:
                        logging.debug("Check file existence one by one, %s", e)
                        continue
                    if data['have']:
                        # ファイル所持Nodeを発見したのでGETを即送信
                        hopeful = ask_user
                        break
                    elif not data['asked']:
                        candidates.append(ask_user)
                    else:
                        pass
                else:
                    # 候補がいなければここで探索終了
                    if len(candidates) == 0:
                        temperate['type'] = T_RESPONSE
                        self._send_msg(item=temperate, allows=[user], denys=list())
                        logging.debug("Asking, stop asking file.")
                        return
                    else:
                        hopeful = random.choice(candidates)  # 一番新しいのを候補

                logging.debug("Asking, Candidate={}, ask=>{}".format(len(candidates), hopeful.name))
                try:
                    data = {'hash': file_hash, 'asked': nears_name}
                    self.__user2user_route.put(uuid=item['uuid'], item=(user, hopeful))
                    from_client, data = self.send_command(ClientCmd.FILE_GET, data,
                                                          item['uuid'], user=hopeful, timeout=5)
                    temperate['data'] = data
                    if data is None:
                        logging.debug("Asking failed from {} {}".format(hopeful.name, file_hash))
                    else:
                        logging.debug("Asking success {} {}".format(hopeful.name, file_hash))
                except Exception as e:
                    logging.debug("Asking raised {} {} {}".format(hopeful.name, file_hash, e))
                    temperate['data'] = None
                temperate['type'] = T_RESPONSE
                count = self._send_msg(item=temperate, allows=[user], denys=list())
                logging.debug("Response file to {} {}({})".format(user.name, count, file_hash))
                return

            def sending():
                with open(file_path, mode='br') as f:
                    raw = f.read()
                temperate['type'] = T_RESPONSE
                temperate['data'] = raw
                self.__user2user_route.put(uuid=item['uuid'], item=(user, user))
                if 0 < self._send_msg(item=temperate, allows=[user], denys=list()):
                    logging.debug("Send file to {} {}".format(user.name, file_hash))
                else:
                    logging.debug("Failed send file to {} {}".format(user.name, file_hash))

            if self.__user2user_route.include(item['uuid']):
                return
            logging.debug("Asked file get by {}".format(user.name))
            file_hash = item['data']['hash']
            already_asked_user = set(item['data']['asked'])
            file_path = os.path.join(V.TMP_PATH, 'file.' + file_hash + '.dat')
            # When you have file, sending. When you don't have file, asking
            if os.path.exists(file_path):
                Thread(target=sending, name='Sending', daemon=True).start()
            elif V.F_FILE_CONTINUE_ASKING:
                # Default disable
                Thread(target=asking, name='Asking', daemon=True).start()

        elif item['cmd'] == ClientCmd.FILE_DELETE:
            item_ = item['data']
            file_hash = item_['hash']
            signer_pk = item_['signer']
            sign = item_['sign']
            cert_sign = item_['cert']['sign']
            master_pk = item_['cert']['master']
            cert_start = item_['cert']['start']
            cert_stop = item_['cert']['stop']

            if not(cert_start < int(time.time()) < cert_stop):
                return  # old signature
            elif master_pk not in C.MASTER_KEYS:
                return
            elif item['uuid'] in self.__broadcast_uuid:
                return  # already get broadcast data
            elif self.__waiting_result.include(item['uuid']):
                return  # I'm broadcaster, get from ack

            self.__broadcast_uuid.append(item['uuid'])
            cert_raw = bjson.dumps((master_pk, signer_pk, cert_start, cert_stop), compress=False)
            sign_raw = bjson.dumps((file_hash, item['uuid']), compress=False)
            deny_list.append(user)
            allow_list = None
            # send ACK
            ack_list.append(user)
            # send Response
            temperate['type'] = T_REQUEST
            temperate['data'] = item['data']
            # delete file check
            try:
                logging.debug("1:Delete request {}".format(file_hash))
                ecc = Encryption()
                ecc.pk = master_pk  # 署名者の署名者チェック
                ecc.verify(msg=cert_raw, signature=cert_sign)
                ecc.pk = signer_pk  # 署名者チェック
                ecc.verify(msg=sign_raw, signature=sign)
                if self.remove_file(file_hash):
                    logging.info("2:Delete request accepted!")
            except ValueError:
                allow_list = list()  # No sending

        elif item['cmd'] == ClientCmd.DIRECT_CMD:
            def direct_cmd():
                data = item['data']
                temperate['data'] = self.event.work(cmd=data['cmd'], data=data['data'])
                self._send_msg(item=temperate, allows=[user])
            if 'cmd' in item['data'] and item['data']['cmd'] in self.event:
                Thread(target=direct_cmd, name='DirectCmd', daemon=True).start()
        else:
            pass

        # send message
        send_count = self._send_msg(item=temperate, allows=allow_list, denys=deny_list)
        # send ack
        ack_count = 0
        if len(ack_list) > 0:
            temperate['type'] = T_ACK
            temperate['data'] = send_count
            ack_count = self._send_msg(item=temperate, allows=ack_list)
        # debug
        if Debug.P_RECEIVE_MSG_INFO:
            logging.debug("Reply to request {} All={}, Send={}, Ack={}"
                          .format(temperate['cmd'], len(self.p2p.user), send_count, ack_count))
Пример #26
0
def encode(*args):
    assert len(args) == 3
    return bjson.dumps(args, compress=False)
Пример #27
0
def change_mintcoin(mint_id,
                    cur,
                    amount=None,
                    description=None,
                    image=None,
                    setting=None,
                    new_address=None,
                    gas_price=None,
                    sender=C.ANT_UNKNOWN,
                    retention=10800):
    assert amount or description or image or setting or new_address
    params = dict()
    if description:
        params['description'] = description
    if image:
        params['image'] = image
    if new_address:
        params['address'] = new_address
    if len(params) == 0:
        params = None
    if not params and not setting and not amount:
        raise BlockChainError('No update found.')
    m_before = get_mintcoin_object(coin_id=mint_id)
    if m_before.version == -1:
        raise BlockChainError('Not init mintcoin. {}'.format(m_before))
    result = check_mintcoin_new_format(m_before=m_before,
                                       new_params=params,
                                       new_setting=setting)
    if isinstance(result, str):
        raise BlockChainError('check_mintcoin_new_format(): {}'.format(result))
    msg_body = bjson.dumps((mint_id, params, setting), compress=False)
    tx = TX(
        tx={
            'type': C.TX_MINT_COIN,
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': msg_body
        })
    if amount:
        tx.outputs.append((MINTCOIN_DUMMY_ADDRESS, 0, amount))
        send_coins = Balance(0, amount)
        minting_coins = Balance(mint_id, amount)
    else:
        send_coins = Balance(0, 0)
        minting_coins = Balance(0, 0)
    tx.update_time(retention)
    additional_gas = C.MINTCOIN_GAS + C.SIGNATURE_GAS  # for mint_coin user signature
    tx.gas_amount = tx.size + C.SIGNATURE_GAS + additional_gas
    tx.serialize()
    # fill unspents
    fee_coin_id = 0
    input_address = fill_inputs_outputs(tx=tx,
                                        cur=cur,
                                        fee_coin_id=fee_coin_id,
                                        additional_gas=additional_gas)
    input_address.add(m_before.address)
    fee_coins = Balance(coin_id=fee_coin_id,
                        amount=tx.gas_price * tx.gas_amount)
    # check amount
    check_enough_amount(sender=sender,
                        send_coins=send_coins,
                        fee_coins=fee_coins)
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, cur=cur)
    # replace dummy mint_id
    replace_mint_dummy_address(tx=tx,
                               mint_address=m_before.address,
                               mint_id=mint_id,
                               f_raise=False)
    # setup signature
    tx.serialize()
    setup_signature(tx=tx, input_address=input_address)
    # movement
    movements = Accounting()
    movements[sender] += minting_coins
    movements[C.ANT_OUTSIDE] -= minting_coins
    movements[sender] -= fee_coins
    movements[C.ANT_OUTSIDE] += fee_coins
    insert_log(movements, cur, tx.type, tx.time, tx.hash)
    return tx