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
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_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
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 change_mintcoin(mint_id, cur, amount=0, message=None, additional_issue=None, image=None, sender=C.ANT_UNKNOWN): mint_old = get_mintcoin(mint_id) assert mint_old, 'Not defined MintCoin {}'.format(mint_id) mint_new = MintCoinObject(None) mint_new.version = mint_old.version + 1 mint_new.coin_id = mint_id mint_new.amount = amount mint_new.additional_issue = additional_issue mint_address = get_address(mint_old.owner, prefix=V.BLOCK_PREFIX) uuid, sk, pk = read_address2keypair(mint_address, cur) mint_new.owner = pk mint_new.image = image mint_new.message = message # マージチェック mint_new.marge(mint_old) # Message内署名 mint_new.generate_sign(sk) mint_new.serialize() mint_new.check_param() mint_new.check_sign() logging.info("New Mintcoin skeleton created coin_id={}".format( mint_new.coin_id)) # movement movements = UserCoins() minting_coins = CoinObject(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)] if 0 < amount else list(), 'gas_price': V.COIN_MINIMUM_PRICE, 'gas_amount': 1, 'message_type': C.MSG_BYTE, 'message': mint_new.binary }) tx.gas_amount = tx.getsize() + 96 + C.MINTCOIN_FEE tx.serialize() 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 if amount > 0: replace_mint_dummy_address(tx, mint_address, 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_new, 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 send_many(sender, send_pairs, cur, fee_coin_id=0, gas_price=None, msg_type=C.MSG_NONE, msg_body=b'', f_balance_check=True, retention=10800): assert isinstance(sender, int), 'Sender is user id.' assert 0 < len(send_pairs), 'Empty send_pairs.' # send_pairs check movements = UserCoins() outputs = list() coins = CoinObject() for address, coin_id, amount in send_pairs: assert isinstance( address, str) and len(address) == 40, 'Recipient is 40 letter string.' assert isinstance(coin_id, int) and isinstance( amount, int), 'CoinID, amount is int.' coins[coin_id] += amount outputs.append((address, coin_id, amount)) movements[sender] -= coins movements[C.ANT_OUTSIDE] += coins # tx now = int(time.time() - V.BLOCK_GENESIS_TIME) tx = TX( tx={ 'version': __chain_version__, 'type': C.TX_TRANSFER, 'time': now, 'deadline': now + retention, 'inputs': list(), 'outputs': outputs, 'gas_price': gas_price or V.COIN_MINIMUM_PRICE, 'gas_amount': 1, 'message_type': msg_type, 'message': msg_body }) tx.gas_amount = tx.size + C.SIGNATURE_GAS # fill unspents input_address = fill_inputs_outputs(tx, cur, fee_coin_id, additional_gas=0) # account check fee_coins = CoinObject(coin_id=fee_coin_id, amount=tx.gas_price * tx.gas_amount) if f_balance_check: # 残高が十分にあるかチェック send_coins = CoinObject() for address, coin_id, amount in send_pairs: send_coins[coin_id] += amount 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 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
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 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