def contract_fill(c: Contract, best_block=None, best_chain=None, stop_txhash=None): # database c_iter = builder.db.read_contract_iter(c_address=c.c_address, start_idx=c.db_index) for index, start_hash, finish_hash, (c_method, c_args, c_storage) in c_iter: if start_hash == stop_txhash or finish_hash == stop_txhash: return c.update(db_index=index, start_hash=start_hash, finish_hash=finish_hash, c_method=c_method, c_args=c_args, c_storage=c_storage) # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return if tx.type != C.TX_CONCLUDE_CONTRACT: continue c_address, start_hash, c_storage = decode(tx.message) if c_address != c.c_address: continue if start_hash == stop_txhash: return start_tx = tx_builder.get_tx(txhash=start_hash) dummy, c_method, redeem_address, c_args = decode(start_tx.message) index = start_tx2index(start_tx=start_tx) c.update(db_index=index, start_hash=start_hash, finish_hash=tx.hash, c_method=c_method, c_args=c_args, c_storage=c_storage) # unconfirmed (check validator condition satisfied) if best_block is None: unconfirmed = list() for conclude_tx in tuple(tx_builder.unconfirmed.values()): if conclude_tx.hash == stop_txhash: break if conclude_tx.type != C.TX_CONCLUDE_CONTRACT: continue c_address, start_hash, c_storage = decode(conclude_tx.message) if c_address != c.c_address: continue if start_hash == stop_txhash: break start_tx = tx_builder.get_tx(txhash=start_hash) if start_tx.height is None: continue sort_key = start_tx2index(start_tx=start_tx) unconfirmed.append((c_address, start_tx, conclude_tx, c_storage, sort_key)) v = get_validator_object(c_address=c.c_address, best_block=best_block, best_chain=best_chain, stop_txhash=stop_txhash) for c_address, start_tx, conclude_tx, c_storage, sort_key in sorted(unconfirmed, key=lambda x: x[4]): if len(conclude_tx.signature) < v.require: continue # ignore unsatisfied ConcludeTXs dummy, c_method, redeem_address, c_args = decode(start_tx.message) c.update(db_index=sort_key, start_hash=start_tx.hash, finish_hash=conclude_tx.hash, c_method=c_method, c_args=c_args, c_storage=c_storage)
def contract_fill(c: Contract, best_block=None, best_chain=None, stop_txhash=None): assert c.index == -1, 'Already updated' # database c_iter = builder.db.read_contract_iter(c_address=c.c_address) for index, start_hash, finish_hash, (c_method, c_args, c_storage) in c_iter: if finish_hash == stop_txhash: return c.update(start_hash=start_hash, finish_hash=finish_hash, c_method=c_method, c_args=c_args, c_storage=c_storage) # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return if tx.type != C.TX_CONCLUDE_CONTRACT: continue c_address, start_hash, c_storage = decode(tx.message) if c_address != c.c_address: continue start_tx = tx_builder.get_tx(txhash=start_hash) dummy, c_method, c_args = decode(start_tx.message) c.update(start_hash=start_hash, finish_hash=tx.hash, c_method=c_method, c_args=c_args, c_storage=c_storage) # unconfirmed if best_block is None: for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time): if tx.hash == stop_txhash: return if tx.type != C.TX_CONCLUDE_CONTRACT: continue c_address, start_hash, c_storage = decode(tx.message) if c_address != c.c_address: continue start_tx = tx_builder.get_tx(txhash=start_hash) dummy, c_method, c_args = decode(start_tx.message) c.update(start_hash=start_hash, finish_hash=tx.hash, c_method=c_method, c_args=c_args, c_storage=c_storage)
def validator_fill(v: Validator, best_block=None, best_chain=None, stop_txhash=None): # database v_iter = builder.db.read_validator_iter(c_address=v.c_address, start_idx=v.db_index) for index, address, flag, txhash, sig_diff in v_iter: if txhash == stop_txhash: return v.update(db_index=index, flag=flag, address=address, sig_diff=sig_diff, txhash=txhash) # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return if tx.type != C.TX_VALIDATOR_EDIT: continue c_address, address, flag, sig_diff = decode(tx.message) if c_address != v.c_address: continue index = validator_tx2index(tx=tx) v.update(db_index=index, flag=flag, address=address, sig_diff=sig_diff, txhash=tx.hash) # unconfirmed if best_block is None: for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time): if tx.hash == stop_txhash: return if tx.type != C.TX_VALIDATOR_EDIT: continue c_address, address, flag, sig_diff = decode(tx.message) if c_address != v.c_address: continue if len(tx.signature) < v.require: continue index = validator_tx2index(tx=tx) v.update(db_index=index, flag=flag, address=address, sig_diff=sig_diff, txhash=tx.hash)
def _get_best_chain_all(best_block): global best_block_cashe, best_chain_cashe # MemoryにおけるBestBlockまでのChainを返す if best_block is None: best_block_cashe = best_chain_cashe = None return builder.best_chain elif best_block_cashe and best_block == best_block_cashe: return best_chain_cashe else: dummy, best_chain = builder.get_best_chain(best_block) # best_chain = [<height=n>, <height=n-1>,.. <height=n-m>] if len(best_chain) == 0: raise BlockChainError('Ignore, New block inserted on "_get_best_chain_all".') best_block_cashe = best_block best_chain_cashe = best_chain return best_chain
def validator_fill(v: Validator, best_block=None, best_chain=None, stop_txhash=None): assert v.index == -1, 'Already updated' # database for index, address, flag, txhash, sig_diff in builder.db.read_validator_iter( c_address=v.c_address): if txhash == stop_txhash: return v.update(flag=flag, address=address, sig_diff=sig_diff, txhash=txhash) # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return if tx.type != C.TX_VALIDATOR_EDIT: continue c_address, address, flag, sig_diff = decode(tx.message) if c_address != v.c_address: continue v.update(flag=flag, address=address, sig_diff=sig_diff, txhash=tx.hash) # unconfirmed if best_block is None: for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time): if tx.hash == stop_txhash: return if tx.type != C.TX_VALIDATOR_EDIT: continue c_address, address, flag, sig_diff = decode(tx.message) if c_address != v.c_address: continue v.update(flag=flag, address=address, sig_diff=sig_diff, txhash=tx.hash)
def get_conclude_hash_by_start_hash(c_address, start_hash, best_block=None, best_chain=None, stop_txhash=None): # database c_iter = builder.db.read_contract_iter(c_address=c_address) for index, _start_hash, finish_hash, (c_method, c_args, c_storage) in c_iter: if finish_hash == stop_txhash: return None if _start_hash == start_hash: return finish_hash # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return None if tx.type != C.TX_CONCLUDE_CONTRACT: continue _c_address, _start_hash, c_storage = decode(tx.message) if _c_address != c_address: continue if _start_hash == start_hash: return tx.hash # unconfirmed if best_block is None: for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time): if tx.hash == stop_txhash: return None if tx.type != C.TX_CONCLUDE_CONTRACT: continue _c_address, _start_hash, c_storage = decode(tx.message) if _c_address != c_address: continue if _start_hash == start_hash: return tx.hash return None
def fill_mintcoin_status(m, best_block=None, best_chain=None, stop_txhash=None): assert m.version == -1, 'Already updated' # database for index, txhash, params, setting in builder.db.read_coins_iter( coin_id=m.coin_id): if txhash == stop_txhash: return m.update(params=params, setting=setting, txhash=txhash) # memory if best_chain: _best_chain = None elif best_block and best_block == builder.best_block: _best_chain = builder.best_chain else: dummy, _best_chain = builder.get_best_chain(best_block=best_block) for block in reversed(best_chain or _best_chain): for tx in block.txs: if tx.hash == stop_txhash: return if tx.type != C.TX_MINT_COIN: continue coin_id, params, setting = decode(tx.message) if coin_id != m.coin_id: continue m.update(params=params, setting=setting, txhash=tx.hash) # unconfirmed if best_block is None: for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time): if tx.hash == stop_txhash: return if tx.type != C.TX_MINT_COIN: continue coin_id, params, setting = decode(tx.message) if coin_id != m.coin_id: continue m.update(params=params, setting=setting, txhash=tx.hash)
def _update_unconfirmed_info(): with unconfirmed_lock: s = time() # sort unconfirmed txs unconfirmed_txs = sorted(tx_builder.unconfirmed.values(), key=lambda x: (x.gas_price, -1 * x.time), reverse=True) # reject tx (input tx is unconfirmed) limit_height = builder.best_block.height - C.MATURE_HEIGHT best_block, best_chain = builder.get_best_chain() used_pairs = set() for tx in unconfirmed_txs.copy(): if tx.height is not None: if tx.hash in tx_builder.unconfirmed: del tx_builder.unconfirmed[tx.hash] unconfirmed_txs.remove(tx) continue if Debug.F_STICKY_TX_REJECTION and tx.hash in sticky_failed_txhash: unconfirmed_txs.remove(tx) continue # inputs check for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) if input_tx is None: unconfirmed_txs.remove(tx) break elif input_tx.height is None: unconfirmed_txs.remove(tx) break elif input_tx.type in (C.TX_POS_REWARD, C.TX_POW_REWARD) and \ input_tx.height > limit_height: unconfirmed_txs.remove(tx) break elif is_usedindex(txhash, txindex, tx.hash, best_block, best_chain): unconfirmed_txs.remove(tx) break # check inputs used same unconfirmed_txs input_pair = (txhash, txindex) if input_pair in used_pairs: unconfirmed_txs.remove(tx) break used_pairs.add(input_pair) # contract tx need_resort_txs = defaultdict(list) for tx in unconfirmed_txs.copy(): if tx.type == C.TX_CONCLUDE_CONTRACT: try: c_address, start_hash, c_storage = bjson.loads(tx.message) except Exception: unconfirmed_txs.remove(tx) # failed decode bjson continue start_tx = tx_builder.get_tx(txhash=start_hash) if start_tx is None or start_tx.height is None: unconfirmed_txs.remove(tx) # start tx is confirmed continue v = get_validator_object(c_address=c_address, best_block=best_block, best_chain=best_chain) signed_cks = get_signed_cks(tx) accept_cks = signed_cks & set(v.validators) if v.require > len(accept_cks): unconfirmed_txs.remove(tx) continue # decide to include the ConcludeTx index = start_tx2index(start_tx=start_tx) need_resort_txs[c_address].append((index, tx)) elif tx.type == C.TX_VALIDATOR_EDIT: try: c_address, address, flag, sig_diff = bjson.loads( tx.message) except Exception: unconfirmed_txs.remove(tx) # failed decode bjson continue v = get_validator_object(c_address=c_address, best_block=best_block, best_chain=best_chain) signed_cks = get_signed_cks(tx) accept_cks = signed_cks & set(v.validators) if v.require > len(accept_cks): unconfirmed_txs.remove(tx) continue else: pass # affect resort txs (for contract) if len(need_resort_txs) > 0: append_txs = list() for c_address, data_list in need_resort_txs.items(): if len(data_list) < 2: continue for index, tx in sorted(data_list, key=lambda x: x[0]): unconfirmed_txs.remove(tx) append_txs.append(tx) else: unconfirmed_txs.extend(append_txs) # limit per tx's in block if Debug.F_LIMIT_INCLUDE_TX_IN_BLOCK: unconfirmed_txs = unconfirmed_txs[:Debug. F_LIMIT_INCLUDE_TX_IN_BLOCK] update_unconfirmed_txs(unconfirmed_txs) logging.debug("Update unconfirmed={}/{} {}Sec".format( len(unconfirmed_txs), len(tx_builder.unconfirmed), round(time() - s, 3)))
def _update_unconfirmed_info(): with unconfirmed_lock: s = time() # sort unconfirmed txs unconfirmed_txs = sorted(tx_builder.unconfirmed.values(), key=lambda x: x.gas_price, reverse=True) # reject tx (input tx is unconfirmed) limit_height = builder.best_block.height - C.MATURE_HEIGHT best_block, best_chain = builder.get_best_chain() used_pairs = set() for tx in unconfirmed_txs.copy(): if tx.height is not None: if tx.hash in tx_builder.unconfirmed: del tx_builder.unconfirmed[tx.hash] unconfirmed_txs.remove(tx) continue if Debug.F_STICKY_TX_REJECTION and tx.hash in sticky_failed_txhash: unconfirmed_txs.remove(tx) continue for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) if input_tx is None: unconfirmed_txs.remove(tx) break elif input_tx.height is None: unconfirmed_txs.remove(tx) break elif input_tx.type in (C.TX_POS_REWARD, C.TX_POW_REWARD) and \ input_tx.height > limit_height: unconfirmed_txs.remove(tx) break elif is_usedindex(txhash, txindex, tx.hash, best_block, best_chain): unconfirmed_txs.remove(tx) break # check inputs used same unconfirmed_txs input_pair = (txhash, txindex) if input_pair in used_pairs: unconfirmed_txs.remove(tx) break used_pairs.add(input_pair) # limit per tx's in block if Debug.F_LIMIT_INCLUDE_TX_IN_BLOCK: unconfirmed_txs = unconfirmed_txs[:Debug. F_LIMIT_INCLUDE_TX_IN_BLOCK] unconfirmed_txs = sorted(unconfirmed_txs, key=lambda x: x.time) # ContractTXのみ取り出す contract_txs = dict() for tx in unconfirmed_txs.copy(): if tx.type == C.TX_START_CONTRACT: unconfirmed_txs.remove(tx) if tx not in contract_txs: contract_txs[tx] = list() elif tx.type == C.TX_FINISH_CONTRACT: unconfirmed_txs.remove(tx) dummy0, start_hash, dummy1 = bjson.loads(tx.message) if start_hash not in tx_builder.unconfirmed: continue start_tx = tx_builder.unconfirmed[start_hash] if start_tx in contract_txs: contract_txs[start_tx].append(tx) if start_tx in unconfirmed_txs: contract_txs[start_tx] = [tx] # StartTX=>FinishTXを一対一関係で繋げる if len(contract_txs) > 0: _, required_num = get_validator_info() for start_tx, finish_txs in contract_txs.items(): if len(finish_txs) == 0: continue for tx in finish_txs: if len(tx.signature) < required_num: continue # OK! unconfirmed_txs.extend((start_tx, tx)) break update_unconfirmed_txs(unconfirmed_txs) logging.debug("Update unconfirmed={}/{} {}Sec".format( len(unconfirmed_txs), len(tx_builder.unconfirmed), round(time() - s, 3)))