def contract_signature_check(extra_tx: TX, v: Validator, include_block: Block): signed_cks = get_signed_cks(extra_tx) accept_cks = signed_cks & set(v.validators) if include_block: # check satisfy require? if len(accept_cks) < v.require: raise BlockChainError('Not satisfied require signature. [signed={}, accepted={}, require={}]' .format(signed_cks, accept_cks, v.require)) else: # check can marge? original_tx = tx_builder.get_tx(txhash=extra_tx.hash) if original_tx is None: # not accept before if 0 < v.require and len(accept_cks) == 0: raise BlockChainError('No acceptable signature. signed={}'.format(signed_cks)) else: # need to marge signature if original_tx.height is not None: raise BlockChainError('Already included tx. height={}'.format(original_tx.height)) if v.require == 0: raise BlockChainError('Don\t need to marge signature.') original_cks = get_signed_cks(original_tx) accept_new_cks = (signed_cks - original_cks) & set(v.validators) if len(accept_new_cks) == 0: raise BlockChainError('No new acceptable cks. ({} - {}) & {}' .format(signed_cks, original_cks, set(v.validators)))
def check_tx_time(tx): # For unconfirmed tx now = int(time.time()) - V.BLOCK_GENESIS_TIME if tx.type in (C.TX_VALIDATOR_EDIT, C.TX_CONCLUDE_CONTRACT): if not (tx.time - C.ACCEPT_MARGIN_TIME < now < tx.deadline + C.ACCEPT_MARGIN_TIME): raise BlockChainError( 'TX time is not correct range. {}<{}<{}'.format( tx.time - C.ACCEPT_MARGIN_TIME, now, tx.deadline + C.ACCEPT_MARGIN_TIME)) else: if tx.time > now + C.ACCEPT_MARGIN_TIME: raise BlockChainError('TX time too early. {}>{}+{}'.format( tx.time, now, C.ACCEPT_MARGIN_TIME)) if tx.deadline < now - C.ACCEPT_MARGIN_TIME: raise BlockChainError('TX time is too late. [{}<{}-{}]'.format( tx.deadline, now, C.ACCEPT_MARGIN_TIME)) # common check if tx.deadline - tx.time < 10800: raise BlockChainError( 'TX acceptable spam is too short. {}-{}<{}'.format( tx.deadline, tx.time, 10800)) if tx.deadline - tx.time > 43200: # 12hours raise BlockChainError( 'TX acceptable spam is too long. {}-{}<{}'.format( tx.deadline, tx.time, 10800))
def update_work_hash(block): if block.flag == C.BLOCK_GENESIS: block.work_hash = b'\xff' * 32 elif block.flag == C.BLOCK_COIN_POS: proof_tx = block.txs[0] if proof_tx.pos_amount is None: from bc4py.database.builder import tx_builder txhash, txindex = proof_tx.inputs[0] output_tx = tx_builder.get_tx(txhash) if output_tx is None: raise BlockChainError('Not found output {} of {}'.format( proof_tx, block)) address, coin_id, amount = output_tx.outputs[txindex] proof_tx.pos_amount = amount block.work_hash = get_stake_coin_hash( tx=proof_tx, previous_hash=block.previous_hash) elif block.flag == C.BLOCK_CAP_POS: proof_tx = block.txs[0] address, coin_id, amount = proof_tx.outputs[0] scope_hash = poc_hash(address=address, nonce=block.nonce) index = scope_index(block.previous_hash) block.work_hash = poc_work(time=block.time, scope_hash=scope_hash[index * 32:index * 32 + 32], previous_hash=block.previous_hash) elif block.flag == C.BLOCK_FLK_POS: raise BlockChainError("unimplemented") else: # POW_??? hash_fnc = get_workhash_fnc(block.flag) block.work_hash = hash_fnc(block.b)
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 ask_node(cmd, data=None, f_continue_asking=False): check_connection() count = 10 pc = V.PC_OBJ user_list = pc.p2p.user.copy() random.shuffle(user_list) while 0 < count: try: if len(user_list) == 0: raise BlockChainError('Asked all nodes, no node to ask.') user = user_list.pop() if user in bad_node: count -= 1 continue elif user not in good_node: set_good_node() if len(good_node) == 0: raise BlockChainError('No good node found.') else: logging.debug("Get good node {}".format(len(good_node))) continue dummy, r = pc.send_direct_cmd(cmd=cmd, data=data, user=user) if f_continue_asking and isinstance(r, str): if count > 0: logging.warning( "Failed DirectCmd:{} to {} by \"{}\"".format( cmd, user.name, r)) count -= 1 continue else: raise BlockChainError('Node return error "{}"'.format(r)) except TimeoutError: continue return r raise BlockChainError('Too many retry ask_node.')
def amount_check(tx, payfee_coin_id): # Inputs input_coins = Balance() for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) if input_tx is None: raise BlockChainError('Not found input tx {}'.format(txhash.hex())) address, coin_id, amount = input_tx.outputs[txindex] input_coins[coin_id] += amount # Outputs output_coins = Balance() for address, coin_id, amount in tx.outputs: if amount <= 0: raise BlockChainError('Input amount is more than 0') output_coins[coin_id] += amount # Fee fee_coins = Balance(coin_id=payfee_coin_id, amount=tx.gas_price * tx.gas_amount) # Check all plus amount remain_amount = input_coins - output_coins - fee_coins if not remain_amount.is_empty(): raise BlockChainError( '77 Don\'t match input/output. {}={}-{}-{}'.format( remain_amount, input_coins, output_coins, fee_coins))
def amount_check(tx, payfee_coin_id): # Inputs input_coins = CoinObject() for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) if input_tx is None: raise BlockChainError('Not found input tx {}'.format( hexlify(txhash).decode())) address, coin_id, amount = input_tx.outputs[txindex] input_coins[coin_id] += amount # Outputs output_coins = CoinObject() for address, coin_id, amount in tx.outputs: if amount <= 0: raise BlockChainError('Input amount is more than 0') output_coins[coin_id] += amount # Fee fee_coins = CoinObject(coin_id=payfee_coin_id, amount=tx.gas_price * tx.gas_amount) # Check all plus amount remain_amount = input_coins - output_coins - fee_coins if not remain_amount.is_all_plus_amount(): raise BlockChainError( 'There are minus amount coins. {}={}-{}-{}'.format( remain_amount, input_coins, output_coins, fee_coins))
def start_tx2index(start_hash=None, start_tx=None): if start_hash: start_tx = tx_builder.get_tx(txhash=start_hash) block = builder.get_block(blockhash=builder.get_block_hash(height=start_tx.height)) if block is None: raise BlockChainError('Not found block of start_tx included? {}'.format(start_tx)) if start_tx not in block.txs: raise BlockChainError('Not found start_tx in block? {}'.format(block)) return start_tx.height * 0xffffffff + block.txs.index(start_tx)
def check_block(block: Block): # 挿入前にBlockの正当性チェック if len(block.txs) == 0: raise BlockChainError('Block don\'t have any txs') elif block.size > C.SIZE_BLOCK_LIMIT: raise BlockChainError('Block size is too large [{}b>{}b]'.format(block.size, C.SIZE_BLOCK_LIMIT)) bits = get_bits_by_hash(previous_hash=block.previous_hash, consensus=block.flag)[0] if block.bits != bits: raise BlockChainError('Block bits differ from calc. [{}!={}]'.format(block.bits, bits)) log.debug("check block success {}".format(block))
def check_block(block: Block): # 挿入前にBlockの正当性チェック if block.f_orphan: raise BlockChainError('Block is orphan.') elif len(block.txs) == 0: raise BlockChainError('Block don\'t have any txs.') elif block.getsize() > C.SIZE_BLOCK_LIMIT: raise BlockChainError('Block size is too large [{}b>{}b]'.format(block.getsize(), C.SIZE_BLOCK_LIMIT)) bits = get_bits_by_hash(previous_hash=block.previous_hash, consensus=block.flag)[0] if block.bits != bits: raise BlockChainError('Block bits differ from calc. [{}!={}]'.format(block.bits, bits)) logging.debug("Checked block {}.".format(block))
def check_output_format(outputs): for o in outputs: if not isinstance(o, tuple): raise BlockChainError('Outputs is tuple.') elif len(o) != 3: raise BlockChainError('Output is three element.') address, coin_id, amount = o if not isinstance(address, str) or len(address) != 40: raise BlockChainError('output address is 40 string. {}'.format(address)) elif not isinstance(coin_id, int) or coin_id < 0: raise BlockChainError('output coin_id is 0< int. {}'.format(coin_id)) elif not isinstance(amount, int) or not(amount > 0): raise BlockChainError('output amount is 0<= int. {}'.format(amount))
def check_tx_time(tx): # For unconfirmed tx now = int(time.time()) - V.BLOCK_GENESIS_TIME if tx.time > now + C.ACCEPT_MARGIN_TIME: raise BlockChainError('TX time too early. {}>{}+{}'.format( tx.time, now, C.ACCEPT_MARGIN_TIME)) elif tx.deadline - tx.time < 10800: raise BlockChainError( 'TX acceptable spam is too short. {}-{}<{}'.format( tx.deadline, tx.time, 10800)) elif tx.deadline < now - C.ACCEPT_MARGIN_TIME: raise BlockChainError('TX time is too late. [{}<{}-{}]'.format( tx.deadline, now, C.ACCEPT_MARGIN_TIME))
def check_tx_create_contract(tx: TX, include_block: Block): if len(tx.inputs) == 0 or len(tx.outputs) == 0: raise BlockChainError('No inputs or outputs.') elif tx.message_type != C.MSG_BYTE: raise BlockChainError('create contract tx is bytes msg.') elif V.BLOCK_CONTRACT_PREFIX is None: raise BlockChainError('Not set contract prefix ?') elif V.BLOCK_CONTRACT_PREFIX == V.BLOCK_PREFIX: raise BlockChainError('normal prefix same with contract prefix.') # GAS量チェック estimate_gas = tx.getsize() + C.CONTRACT_CREATE_FEE if estimate_gas > tx.gas_amount: raise BlockChainError('Insufficient gas [{}>{}]'.format( estimate_gas, tx.gas_amount)) # Contractをデコードできるか c_address, c_bin, c_cs = bjson.loads(tx.message) binary2contract(c_bin) # ContractStorageの初期値チェック if c_cs: for k, v in c_cs.items(): if not isinstance(k, bytes) or not isinstance(v, bytes): raise BlockChainError('cs format is wrong. {}'.format(c_cs)) if not is_address(c_address, V.BLOCK_CONTRACT_PREFIX): raise BlockChainError('Is not contract address. {}'.format(c_address)) # 既に登録されていないかチェック cs = get_contract_storage(c_address, include_block) if cs.version != 0: raise BlockChainError('Already created contract. {}'.format(tx))
def validator_tx2index(txhash=None, tx=None): if txhash: tx = tx_builder.get_tx(txhash=txhash) if tx is None: raise BlockChainError('Not found ValidatorTX {}'.format(tx)) if tx.height is None: raise BlockChainError('Not confirmed ValidatorTX {}'.format(tx)) block = chain_builder.get_block(height=tx.height) if block is None: raise BlockChainError( 'Not found block of start_tx included? {}'.format(tx)) if tx not in block.txs: raise BlockChainError('Not found start_tx in block? {}'.format(block)) return tx.height * 0xffffffff + block.txs.index(tx)
def create_validator_edit_tx(v_address, cur, 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(v_address=v_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 = msgpack.packb((v_address, new_address, flag, sig_diff), use_bin_type=True) tx = TX.from_dict( tx={ 'type': C.TX_VALIDATOR_EDIT, 'gas_price': gas_price or V.COIN_MINIMUM_PRICE, 'gas_amount': 0, 'message_type': C.MSG_MSGPACK, 'message': message }) tx.gas_amount = tx.size tx.update_time(retention) # fill unspents additional_gas = C.VALIDATOR_EDIT_GAS + v.require * C.SIGNATURE_GAS input_address = fill_inputs_outputs(tx=tx, cur=cur, additional_gas=additional_gas) assert len(input_address & set(v.validators)) == 0, 'Not implemented?' # replace dummy address replace_redeem_dummy_address(tx=tx, cur=cur) setup_signature(tx, input_address) if v.version > -1 and setup_contract_signature(tx, v.validators) == 0: raise BlockChainError('Cannot sign, you are not validator') 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 check_hash_locked(tx): if len(tx.R) == 0: raise BlockChainError('R of Hash-locked is None type') if len(tx.R) > 64: raise BlockChainError('R is too large {}bytes'.format(len(tx.R))) size = len(tx.message) if size == 20: if RIPEMD160.new(tx.R).digest() != tx.message: raise BlockChainError('Hash-locked check RIPEMD160 failed') elif size == 32: if SHA256.new(tx.R).digest() != tx.message: raise BlockChainError('Hash-locked check SHA256 failed') else: raise BlockChainError( 'H of Hash-locked is not correct size {}'.format(size))
def signature_check(tx): need_cks = set() for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) if input_tx is None: raise BlockChainError('Not found input tx {}'.format(hexlify(txhash).decode())) address, coin_id, amount = input_tx.outputs[txindex] if is_address(address, V.BLOCK_PREFIX): need_cks.add(address) # 通常のアドレスのみ else: raise BlockChainError('Not common address {} {}.'.format(address, tx)) signed_cks = get_signed_cks(tx) if need_cks != signed_cks: raise BlockChainError('Signature verification failed. [{}={}]'.format(need_cks, signed_cks))
async def sign_raw_tx(request): post = await utils.content_type_json_check(request) try: binary = a2b_hex(post['hex']) other_pairs = dict() for sk in post.get('pairs', list()): sk = a2b_hex(sk) keypair: PyKeyPair = PyKeyPair.from_secret_key(sk) r, s = keypair.get_single_sign(binary) pk = keypair.get_public_key() ck = get_address(pk=pk, hrp=V.BECH32_HRP, ver=C.ADDR_NORMAL_VER) other_pairs[ck] = (pk, r, s) tx = TX.from_binary(binary=binary) for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) address, coin_id, amount = input_tx.outputs[txindex] try: tx.signature.append( sign_message_by_address(raw=tx.b, address=address)) except BlockChainError: if address not in other_pairs: raise BlockChainError( 'Not found secret key "{}"'.format(address)) tx.signature.append(other_pairs[address]) data = tx.getinfo() return utils.json_res({ 'hash': data['hash'], 'signature': data['signature'], 'hex': tx.b.hex() }) except Exception: return utils.error_res()
async def change_mint_tx(request): start = time() post = await utils.content_type_json_check(request) with create_db(V.DB_ACCOUNT_PATH, f_strict=True) as db: cur = db.cursor() try: user_name = post.get('from', C.account2name[C.ANT_UNKNOWN]) sender = read_name2userid(user_name, cur) tx = change_mintcoin(mint_id=post['mint_id'], cur=cur, amount=post.get('amount'), description=post.get('description'), image=post.get('image'), setting=post.get('setting'), new_address=post.get('new_address'), sender=sender) if not send_newtx(new_tx=tx, outer_cur=cur): raise BlockChainError('Failed to send new tx') db.commit() return utils.json_res({ 'hash': tx.hash.hex(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3) }) except Exception: return utils.error_res()
async def issue_mint_tx(request): start = time() post = await utils.content_type_json_check(request) with create_db(V.DB_ACCOUNT_PATH, f_strict=True) as db: cur = db.cursor() try: user_name = post.get('from', C.account2name[C.ANT_UNKNOWN]) sender = read_name2userid(user_name, cur) mint_id, tx = issue_mintcoin( name=post['name'], unit=post['unit'], digit=post.get('digit', 8), amount=post['amount'], cur=cur, description=post.get('description', None), image=post.get('image', None), additional_issue=post.get('additional_issue', True), sender=sender) if not send_newtx(new_tx=tx, outer_cur=cur): raise BlockChainError('Failed to send new tx') db.commit() return utils.json_res({ 'hash': tx.hash.hex(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3), 'mint_id': mint_id }) except Exception: return utils.error_res()
def update_time(self, retention=10800): if retention < 10800: raise BlockChainError('Retention time is too short') now = int(time()) self.time = now - V.BLOCK_GENESIS_TIME self.deadline = now - V.BLOCK_GENESIS_TIME + retention self.serialize()
def deserialize(self, first_pos=0, f_raise=True): self.version, self.type, self.time, self.deadline, self.gas_price, self.gas_amount,\ self.message_type, input_len, outputs_len, msg_len = struct_tx_header.unpack_from(self.b, first_pos) # inputs pos = first_pos + struct_tx_header.size self.inputs = list() for i in range(input_len): self.inputs.append(struct_inputs.unpack_from(self.b, pos)) pos += struct_inputs.size # outputs self.outputs = list() for i in range(outputs_len): b_address, coin_id, amount = struct_outputs.unpack_from( self.b, pos) self.outputs.append((bin2addr(b=b_address, hrp=V.BECH32_HRP), coin_id, amount)) pos += struct_outputs.size # msg self.message = self.b[pos:pos + msg_len] pos += msg_len if len(self.b) != pos - first_pos: if f_raise: raise BlockChainError('Do not match len [{}!={}'.format( len(self.b), pos)) else: self.b = self.b[first_pos:pos] self.hash = sha256d_hash(self.b)
async def sign_raw_tx(request): post = await web_base.content_type_json_check(request) try: binary = unhexlify(post['hex'].encode()) other_pairs = dict() for sk in post.get('pairs', list()): pk = public_key(sk=sk) ck = get_address(pk=pk, prefix=V.BLOCK_PREFIX) other_pairs[ck] = (pk, sign(msg=binary, sk=sk, pk=pk)) tx = TX(binary=binary) for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) address, coin_id, amount = input_tx.outputs[txindex] try: tx.signature.append( message2signature(raw=tx.b, address=address)) except BlockChainError: if address not in other_pairs: raise BlockChainError( 'Not found secret key "{}"'.format(address)) tx.signature.append(other_pairs[address]) data = tx.getinfo() return web_base.json_res({ 'hash': data['hash'], 'signature': data['signature'], 'hex': hexlify(tx.b).decode() }) except BaseException: return web_base.error_res()
def ask_node(cmd, data=None, f_continue_asking=False): check_network_connection() failed = 0 pc = V.PC_OBJ user_list = pc.p2p.user.copy() random.shuffle(user_list) while failed < 10: try: if len(user_list) == 0: break if len(good_node) == 0: set_good_node() user = user_list.pop() if user in good_node: dummy, r = pc.send_direct_cmd(cmd=cmd, data=data, user=user) if isinstance(r, str): failed += 1 if f_continue_asking: logging.warning("Failed cmd={} to {} by \"{}\"".format(cmd, user.name, r)) continue return r elif user in bad_node: pass else: set_good_node() except TimeoutError: pass raise BlockChainError('Too many retry ask_node. good={} bad={} failed={} cmd={}' .format(len(good_node), len(bad_node), failed, cmd))
def replace_mint_dummy_address(tx, mint_address, mint_id): for index, (address, coin_id, amount) in enumerate(tx.outputs): if address == MINTCOIN_DUMMY_ADDRESS: tx.outputs[index] = (mint_address, mint_id, amount) break else: raise BlockChainError('Cannot replace Mintcoin dummy address.')
def result(self): data = self.parent_conn.recv() self.lock.release() if isinstance(data, tuple): return data else: raise BlockChainError('Unknown status on pipe {}'.format(data))
def subtract_fee_from_user_balance(tx: TX): """subtract fee from user's sending outputs""" subtract_fee = tx.gas_amount * tx.gas_price f_subtracted = False f_added = False for index, (address, coin_id, amount) in enumerate(tx.outputs): if coin_id != 0: continue elif amount < subtract_fee: continue elif not f_added and address == DUMMY_REDEEM_ADDRESS: # add used fee to redeem output tx.outputs[index] = (address, coin_id, amount + subtract_fee) f_added = True elif not f_subtracted and address != DUMMY_REDEEM_ADDRESS: # subtract used fee from sending output tx.outputs[index] = (address, coin_id, amount - subtract_fee) f_subtracted = True else: continue # check if f_subtracted is False or f_added is False: raise BlockChainError('failed to subtract fee sub={} add={} fee={}' .format(f_subtracted, f_added, subtract_fee)) return subtract_fee
def update(self, params, setting, txhash): if self.version == -1: self.name = params['name'] self.unit = params['unit'] self.digit = params['digit'] self.address = params['address'] self.description = params.get('description') self.image = params.get('image') if setting is not None: self.setting.update(setting) else: if params is not None: if self.setting['change_address'] and 'address' in params: self.address = params['address'] if self.setting['change_description'] and 'description' in params: self.description = params['description'] if self.setting['change_image'] and 'image' in params: self.image = params['image'] if setting is not None: for k in setting_template.keys(): if k not in setting: continue assert isinstance(self.setting[k], bool) and isinstance(setting[k], bool) if self.setting[k] and setting[k]: # true => true pass elif self.setting[k]: # true => false self.setting[k] = False elif setting[k]: # false => true raise BlockChainError('Not allowed change setting to True. {}'.format(k)) else: # false => false pass self.txhash = txhash self.version += 1
def validator_check(tx, include_block): assert tx.type == C.TX_FINISH_CONTRACT, 'validator_check is for FinishTX.' validator_cks, required_num = get_validator_info(include_block) already_signed_num = tx.inner_params.get('signed_num', 0) signed_cks = get_signed_cks(tx) valid_num = len(validator_cks & signed_cks) if include_block: if required_num > valid_num: raise BlockChainError( 'Not satisfied required sign num. [{}>{}&{}]'.format( required_num, len(validator_cks), len(signed_cks))) else: if already_signed_num >= valid_num: raise BlockChainError('Not found any change {}.'.format(tx)) tx.inner_params['signed_num'] = valid_num