async def chain_info(request): best_height = builder.best_block.height best_block = builder.best_block old_block_height = builder.best_chain[0].height - 1 old_block_hash = hexlify(builder.get_block_hash(old_block_height)).decode() data = {'best': best_block.getinfo()} difficulty = dict() for consensus, ratio in V.BLOCK_CONSENSUSES.items(): name = C.consensus2name[consensus] target = get_bits_by_hash(previous_hash=best_block.hash, consensus=consensus)[1] block_time = round(V.BLOCK_TIME_SPAN / ratio * 100) diff = (MAX_256_INT // target) / 100000000 bias = get_bias_by_hash(previous_hash=best_block.previous_hash, consensus=consensus) difficulty[name] = { 'number': consensus, 'diff': round(diff / 100000000, 8), 'bias': round(bias, 8), 'fixed_diff': round(diff / bias, 8), 'hashrate(kh/s)': round((MAX_256_INT//target)/block_time/1000, 3), 'is_base': V.BLOCK_BASE_CONSENSUS == consensus, } data['mining'] = difficulty data['size'] = best_block.getsize() data['checkpoint'] = {'height': old_block_height, 'blockhash': old_block_hash} data['money_supply'] = GompertzCurve.calc_total_supply(best_height) data['total_supply'] = GompertzCurve.k return web_base.json_res(data)
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)
async def get_block_by_height(request): height = int(request.query.get('height', 0)) blockhash = builder.get_block_hash(height) if blockhash is None: return web.Response(text="Not found height.", status=400) block = builder.get_block(blockhash) data = block.getinfo() data['size'] = block.getsize() data['hex'] = hexlify(block.b).decode() return web_base.json_res(data)
def _big_blocks(height): data = list() for i in range(20): blockhash = builder.get_block_hash(height + i) if blockhash is None: break block = builder.get_block(blockhash) if block is None: break txs = [(tx.b, tx.signature) for tx in block.txs] data.append((block.b, block.height, block.flag, txs)) # TODO:一度に送信できるBytesにチェック return data
async def get_block_by_height(request): f_pickled = request.query.get('pickle', False) height = int(request.query['height']) blockhash = builder.get_block_hash(height) if blockhash is None: return web.Response(text="Not found height.", status=400) block = builder.get_block(blockhash) if f_pickled: block = pickle.dumps(block) return web_base.json_res(b64encode(block).decode()) data = block.getinfo() data['size'] = block.getsize() data['hex'] = hexlify(block.b).decode() return web_base.json_res(data)
def try_emulate(start_tx, gas_limit=None, out=None): start_time = time.time() cxt = get_context('spawn') que = cxt.Queue() # out = out or io.StringIO() c_address, c_method, c_args, c_redeem = bjson.loads(start_tx.message) c_bin = get_contract_binary(c_address) assert c_bin, 'Not found c_bin of {}'.format(c_address) params = { 'sub_dir': V.SUB_DIR, 'genesis_block': builder.get_block(builder.get_block_hash(0)), 'c_bin': c_bin, 'c_address': c_address, 'c_method': c_method, 'args': c_args} p = cxt.Process(target=_work, args=(params, start_tx, que)) p.start() que_cmd, port = que.get(timeout=10) if que_cmd != CMD_PORT: raise TypeError('Not correct command="{}" data="{}"'.format(que_cmd, port)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("127.0.0.1", port)) sock.settimeout(10) # Start emulation line = fee = 0 cmd = EMU_STEP error = None logging.debug("Start contract emulate port={}".format(port)) while True: try: msg_list = sock.recv(8192).decode(errors='ignore').replace("\r", "").split("\n") if len(msg_list) <= 1: sock.close() break elif len(msg_list) < 3: pass elif gas_limit and fee > gas_limit: error = 'reached gas limit. [{}>{}]'.format(fee, gas_limit) break elif cmd in (EMU_STEP, EMU_NEXT, EMU_UNTIL, EMU_RETURN): msg_list, path, words = msg_list[:-3], msg_list[-3][2:], msg_list[-2][3:] file = os.path.split(path)[1] print(file, words, path) if file.startswith('exe.py') and file.endswith('work_field()'): cmd = EMU_STEP # Start! print("start contract {}", file=out) elif file.startswith('contract('): line += 1 fee += 1 cmd = EMU_STEP else: cmd = EMU_NEXT # Add fee for func, gas in __price__.items(): if func in words and words.startswith('def ' + func + '('): fee += gas print("{}:read [{}] {} >> {}".format(line, fee, cmd, words), file=out) else: msg = ', '.join(msg_list) print("msg [{}] >>".format(cmd), msg, file=out) # response to work field sock.send((cmd + "\n").encode()) except ConnectionResetError: break except BaseException: error = str(traceback.format_exc()) break logging.debug("Finish contract {}Sec error:{}".format(round(time.time() - start_time, 3), error)) # Close emulation try: que_cmd, result = que.get_nowait() print(result) try: que.close() except: pass try: p.terminate() except: pass if que_cmd == CMD_ERROR: return False, result, fee, line elif que_cmd == CMD_SUCCESS: return True, result, fee, line except BaseException: return False, error, fee, line
def _block_by_height(height): blockhash = builder.get_block_hash(height) if blockhash: return {'blockhash': blockhash} else: return 'Not found block height {}.'.format(height)
def fast_sync_chain(): assert V.PC_OBJ is not None, "Need PeerClient start before." global f_changed_status, back_thread # wait for back_thread is closed status count = 0 while back_thread and back_thread.is_alive(): block_stack.clear() sleep(1) count += 1 if count % 30 == 0: logging.warning( "Waiting for back_thread closed... {}Sec".format(count)) back_thread = Thread(target=background_process, name='BackSync', daemon=True) back_thread.start() start = time() # 外部Nodeに次のBlockを逐一尋ねる failed_num = 0 before_block = builder.best_block index_height = before_block.height + 1 logging.debug("Start fast sync by {}".format(before_block)) while failed_num < 5: if index_height in block_stack: new_block = block_stack[index_height] with write_protect_lock: del block_stack[index_height] elif backend_processing_lock.locked(): sleep(0.1) continue else: with backend_processing_lock: logging.debug( "Stack blocks on front form {}".format(index_height)) r = ask_node(cmd=DirectCmd.BIG_BLOCKS, data={'height': index_height}) if isinstance(r, str): logging.debug("NewBLockGetError:{}".format(r)) before_block = builder.get_block( before_block.previous_hash) index_height = before_block.height + 1 failed_num += 1 continue elif isinstance(r, list): waiter = Waiter(0) waiter.set() waiter = put_to_block_stack(r, waiter) if waiter is None or len(block_stack) == 0: break else: waiter.wait() continue else: failed_num += 1 logging.debug("Not correct format BIG_BLOCKS.") continue # Base check base_check_failed_msg = None if before_block.hash != new_block.previous_hash: base_check_failed_msg = "Not correct previous hash new={} before={}".format( new_block, before_block) # proof of work check if not new_block.pow_check(): base_check_failed_msg = "Not correct work hash {}".format( new_block) # rollback if base_check_failed_msg is not None: failed_num += 1 for height in tuple(block_stack.keys()): if height >= index_height: del block_stack[height] next_index_block = index_height - 1 editable_height = builder.root_block.height + 1 if next_index_block <= editable_height: logging.error("Try to rollback to editable height {}".format( editable_height)) f_changed_status = False return False elif next_index_block not in block_stack: # back 20 height, no blocks to recombine in block_stack index_height = max(3, editable_height, index_height - 20) index_block = builder.get_block( blockhash=builder.get_block_hash(index_height)) before_block = builder.get_block( blockhash=index_block.previous_hash) with write_protect_lock: block_stack.clear() block_stack[index_height] = index_block else: # back 1 height before_block = builder.get_block(before_block.previous_hash) index_height = before_block.height + 1 logging.debug(base_check_failed_msg) continue # TX check if len(new_block.txs) > 1: with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() for tx in new_block.txs: if tx.type in (C.TX_POS_REWARD, C.TX_POW_REWARD): continue check_tx(tx=tx, include_block=None) tx_builder.put_unconfirmed(tx=tx, outer_cur=cur) db.commit() # Block check check_block(new_block) for tx in new_block.txs: tx.height = new_block.height check_tx(tx=tx, include_block=new_block) # Chainに挿入 builder.new_block(new_block) for tx in new_block.txs: user_account.affect_new_tx(tx) builder.batch_apply() f_changed_status = True # 次のBlock failed_num = 0 before_block = new_block index_height = before_block.height + 1 # ロギング if index_height % 100 == 0: logging.debug("Update block {} now...".format(index_height + 1)) # Unconfirmed txを取得 logging.info("Finish get block, next get unconfirmed.") unconfirmed_txhash_set = set() for data in ask_all_nodes(cmd=DirectCmd.UNCONFIRMED_TX): unconfirmed_txhash_set.update(data['txs']) for txhash in unconfirmed_txhash_set: if txhash in tx_builder.unconfirmed: continue try: r = ask_node(cmd=DirectCmd.TX_BY_HASH, data={'txhash': txhash}, f_continue_asking=True) tx = TX(binary=r['tx']) tx.signature = r['sign'] check_tx_time(tx) check_tx(tx, include_block=None) tx_builder.put_unconfirmed(tx) except BlockChainError: logging.debug("Failed get unconfirmed {}".format( hexlify(txhash).decode())) # 最終判断 reset_good_node() set_good_node() my_best_height = builder.best_block.height best_height_on_network, best_hash_on_network = get_best_conn_info() if best_height_on_network <= my_best_height: logging.info( "Finish update chain data by network. {}Sec [best={}, now={}]". format(round(time() - start, 1), best_height_on_network, my_best_height)) return True else: logging.debug("Continue update chain, best={}, now={}".format( best_height_on_network, my_best_height)) return False