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
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
def replace_redeem_dummy_address(tx, cur): new_redeem_address = set() for index, (address, coin_id, amount) in enumerate(tx.outputs): if address != DUMMY_REDEEM_ADDRESS: continue new_address = create_new_user_keypair(C.ANT_NAME_UNKNOWN, cur) tx.outputs[index] = (new_address, coin_id, amount) new_redeem_address.add(new_address) tx.serialize() return new_redeem_address
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
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
def issue_mintcoin(name, unit, amount, digit, cur, gas_price=None, message='', additional_issue=True, image=None, sender=C.ANT_UNKNOWN): mint = MintCoinObject(None) new_mint_id = get_new_coin_id() mint.version = 0 mint.coin_id = new_mint_id mint.name = name mint.unit = unit mint.digit = digit mint.supply_before = 0 mint.amount = amount mint.additional_issue = additional_issue new_mint_address = create_new_user_keypair(C.ANT_NAME_UNKNOWN, cur) uuid, sk, pk = read_address2keypair(new_mint_address, cur) mint.owner = pk mint.image = image mint.message = message # Message内署名 mint.generate_sign(sk) mint.serialize() mint.check_param() mint.check_sign() logging.info("New Mintcoin skeleton created coin_id={}".format( mint.coin_id)) # movement movements = UserCoins() minting_coins = CoinObject(new_mint_id, amount) movements[sender] += minting_coins movements[C.ANT_OUTSIDE] -= minting_coins # TXを作成する base_coin_id = 0 now = int(time.time()) - V.BLOCK_GENESIS_TIME tx = TX( tx={ 'version': __chain_version__, 'type': C.TX_MINT_COIN, 'time': now, 'deadline': now + 10800, 'inputs': list(), 'outputs': [(MINTCOIN_DUMMY_ADDRESS, base_coin_id, amount)], 'gas_price': gas_price or V.COIN_MINIMUM_PRICE, 'gas_amount': 1, 'message_type': C.MSG_BYTE, 'message': mint.binary }) tx.gas_amount = tx.getsize() + 96 + C.MINTCOIN_FEE tx.serialize() # fill unspents fee_coin_id = 0 input_address = fill_inputs_outputs(tx, cur, fee_coin_id, C.MINTCOIN_FEE) fee_coins = CoinObject(fee_coin_id, tx.gas_price * tx.gas_amount) # check amount check_enough_amount(sender, CoinObject(base_coin_id, amount), fee_coins) # replace dummy address replace_redeem_dummy_address(tx, cur) # replace dummy mint_id replace_mint_dummy_address(tx, new_mint_address, new_mint_id) # 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 mint, tx
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
def new_key(user=C.ANT_NAME_UNKNOWN): with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() ck = create_new_user_keypair(user, cur) db.commit() return ck
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