def reaccept_wallet_txs(): # Reaccept any txes of ours that aren't already in a block txdb = Tx.PyTxDB("r") with ctx.dictWalletLock: for tx_hash, wtx in ctx.dictWallet.iteritems(): if not wtx.is_coinbase() and not txdb.contains_tx(wtx.get_hash()): wtx.accept_wallet_transaction(txdb, False) txdb.close()
def test_txdb(): txdb = Tx.PyTxDB() ret = txdb.read_datas(key=(txdb.DBKEY_BLOCKINDEX, 0), types=[(txdb.DBKEY_BLOCKINDEX, Block.PyDiskBlockIndex)], flags=txdb.DB_SET_RANGE) # ret = txdb.read_datas() if ret is not None: for i in ret: print i[0] pass
def test_walletdb2(): # blkaction.load_wallet() # print 'load wallet' txdb = Tx.PyTxDB("r") a = 67279034089938845637059334169987720265371418128753427043266396123319347216136 print 'modify a' ret = txdb.read_txindex(a) print ret ret = txdb.read_datas() for key, value in ret: print key pass
def test_db(): txdb = Tx.PyTxDB() print 'read successful' txdb.close() print 'end txdb' pass
def send_messages(node_to, t, ignore=False): """ :param node_to: :type node_to: net.PyNode :param t: :type t: ExitedThread :return: """ t.check_self_shutdown() with ctx.mainLock: # Don't send anything until we get their version message if node_to.nVersion == 0: return True # Message: addr list_addr_to_send = [ addr for addr in node_to.list_addr_to_send if addr not in node_to.set_addr_known ] del node_to.list_addr_to_send[:] if list_addr_to_send: node_to.push_message(base.COMMAND_ADDR, list_addr_to_send, ignore=ignore) # Message: inventory list_inventory_to_send = list() with node_to.inventory_lock: for inv in node_to.list_inventory_to_send: if inv not in node_to.set_inventory_know: node_to.set_inventory_know.add(inv) list_inventory_to_send.append(inv) del node_to.list_inventory_to_send[:] # clear element in node.list_inventory_to_send, not local var node_to.set_inventory_know2.clear() # 注意这里clear的是 2 if list_inventory_to_send: node_to.push_message(base.COMMAND_INV, list_inventory_to_send, ignore=ignore) # Message: getdata now = timeutil.get_time() * 1000000 # usec txdb = Tx.PyTxDB("r") list_ask_for = list() dict_ask_for = node_to.dict_ask_for.items( ) # node_to.dict_ask_for is dict dict_ask_for.sort(key=lambda x: x[0]) # sort by key(time:int64) for time, invs in dict_ask_for: if time > now: break for inv in invs: print("sending getdata: %s" % str(inv)) if not already_have(txdb, inv): list_ask_for.append(inv) node_to.dict_ask_for.pop(time, None) if list_ask_for: node_to.push_message(base.COMMAND_GETDATA, list_ask_for, ignore=ignore) txdb.close() pass # end end critical return True
def process_message(node_from, command, recv): """ :param node_from: :type node_from: net.PyNode :param command: :param recv: :type recv: serialize.PyDataStream :return: :rtype bool """ global dictReuseKey print("received: %-12s (%d bytes) " % (command, len(recv))) buf = list() for i in range(min(len(recv), 25)): buf.append("%02x " % (bytearray(recv[i])[0] & 0xff)) print "".join(buf) print("") if ctx.dropMessagesTest > 0 and baseutil.get_rand( ctx.dropMessagesTest) == 0: # 这难吧·· print("dropmessages DROPPING RECV MESSAGE\n") # 应该是模拟随机丢弃消息 return True if command == base.COMMAND_VERSION: # Can only do this once if node_from.nVersion != 0: return False node_from.nVersion = recv.stream_out(out_type="int") # int node_from.services = recv.stream_out(out_type="uint64") # uint64 time = recv.stream_out(out_type="int64") # int64 addr_me = recv.stream_out(cls=net.PyAddress) if node_from.nVersion == 0: return False node_from.send.nVersion = min(node_from.nVersion, cfg.VERSION) node_from.recv.nVersion = min(node_from.nVersion, cfg.VERSION) node_from.f_client = not (node_from.services & cfg.NODE_NETWORK) if node_from.f_client: node_from.send.nType |= serialize.SerType.SER_BLOCKHEADERONLY node_from.recv.nType |= serialize.SerType.SER_BLOCKHEADERONLY timeutil.add_time_data(node_from.addr.ip, time) # Ask the first connected node for block updates global fAskedForBlocks if not fAskedForBlocks and not node_from.f_client: fAskedForBlocks = True node_from.push_message(base.COMMAND_GETBLOCKS, Block.PyBlockLocator(ctx.indexBest), (0, "uint256")) print("version addrMe = %s\n" % str(addr_me)) elif node_from.nVersion == 0: # Must have a version message before anything else return False elif command == base.COMMAND_ADDR: list_addr = recv.stream_out(out_type="list", cls=net.PyAddress) # list<PyAddress> # Store the new addresses addrdb = net.PyAddrDB() for addr in list_addr: if ctx.fShutdown: return True if net.add_address(addrdb, addr): # Put on lists to send to other nodes node_from.set_addr_known.add(addr) with ctx.listNodesLock: if addr not in node_from.set_addr_known: node_from.list_addr_to_send.append(addr) addrdb.close() elif command == base.COMMAND_INV: list_inv = recv.stream_out("list", net.PyInv) txdb = Tx.PyTxDB("r") for inv in list_inv: if ctx.fShutdown: return True node_from.add_inventory_known(inv) f_already_have = already_have(txdb, inv) print(" got inventory: %s %s\n" % (str(inv), "have" if f_already_have else "new")) if not f_already_have: node_from.ask_for(inv) elif inv.msg_type == net.MsgType.MSG_BLOCK and inv.msg_hash in ctx.dictOrphanBlocks: node_from.push_message( base.COMMAND_GETBLOCKS, Block.PyBlockLocator(ctx.indexBest), (Block.get_orphan_root( ctx.dictOrphanBlocks[inv.msg_hash]), "uint256")) txdb.close() elif command == base.COMMAND_GETDATA: list_inv = recv.stream_out("list", net.PyInv) for inv in list_inv: if ctx.fShutdown: return True print("received getdata for: %s\n" % str(inv)) if inv.msg_type == net.MsgType.MSG_BLOCK: # Send block from disk block_index = ctx.dictBlockIndex.get(inv.msg_hash, None) if block_index is not None: ## could optimize this to send header straight from blockindex for client block = Block.PyBlock() block.read_from_disk( block_index, read_txs=( not node_from.f_client)) # index, block_pos=0 node_from.push_message(base.COMMAND_BLOCK, block) elif inv.is_known_type(): # Send stream from relay memory with ctx.dictRelayLock: data = ctx.dictRelay.get(inv, None) # data:PyDataStream if data is not None: node_from.push_message(inv.get_command(), data) elif command == base.COMMAND_GETBLOCKS: locator = recv.stream_out(cls=Block.PyBlockLocator) hash_stop = recv.stream_out(out_type="uint256") # Find the first block the caller has in the main chain index = locator.get_block_index() # Send the rest of the chain if index: index = index.next_index print("getblocks %d to %s\n" % (index.height if index else -1, serialize.hexser_uint256(hash_stop)[:14])) while index: if index.get_block_hash() == hash_stop: print(" getblocks stopping at %d %s" % (index.height, index.get_block_hash(output_type='hex')[:14])) break # Bypass setInventoryKnown in case an inventory message got lost with node_from.inventory_lock: inv = net.PyInv(net.MsgType.MSG_BLOCK, index.get_block_hash()) if inv not in node_from.set_inventory_know2: node_from.set_inventory_know2.add(inv) node_from.set_inventory_know.discard( inv) # not throw exception node_from.list_inventory_to_send.append(inv) index = index.next_index pass # end loop elif command == base.COMMAND_TX: list_work_queue = list() # hash256 list msg = recv.copy() tx = recv.stream_out(cls=Tx.PyTransaction) inv = net.PyInv(net.MsgType.MSG_TX, tx.get_hash()) node_from.add_inventory_known(inv) f_missing_inputs = [False] if tx.accept_transaction(check_inputs=True, missing_inputs=f_missing_inputs): Block.add_to_wallet_if_mine(tx, None) netaction.relay_message(inv, msg) ctx.dictAlreadyAskedFor.pop(inv, None) # delete from dict list_work_queue.append(inv.msg_hash) # Recursively process any orphan transactions that depended on this one for hash_prev in iter(list_work_queue): for msg in ctx.dictOrphanBlocksByPrev[ hash_prev]: # list<PyDataStrem> tx = msg.stream_out(cls=Tx.PyTransaction) inv = net.PyInv(net.MsgType.MSG_TX, tx.get_hash()) if tx.accept_transaction(check_inputs=True): print(" accepted orphan tx %s" % serialize.hexser_uint256(inv.msg_hash)) Block.add_to_wallet_if_mine(tx, None) netaction.relay_message(inv, msg) ctx.dictAlreadyAskedFor.pop(inv, None) # delete from dict list_work_queue.append(inv.msg_hash) pass # end for list_work_queue loop for tx_hash in list_work_queue: txaction.erase_orphan_tx(tx_hash) elif f_missing_inputs[ 0]: # f_missing_inputs will chang in accept_transaction() print("storing orphan tx %s" % serialize.hexser_uint256(inv.msg_hash)[:6]) txaction.add_orphan_tx(msg) elif command == base.COMMAND_REVIEW: msg = recv.copy() review = recv.stream_out(cls=market.PyReview) inv = net.PyInv(net.MsgType.MSG_REVIEW, review.get_hash()) node_from.add_inventory_known(inv) if review.accept_review(): # Relay the original message as-is in case it's a higher version than we know how to parse netaction.relay_message(inv, msg) ctx.dictAlreadyAskedFor.pop(inv, None) # del from dict elif command == base.COMMAND_BLOCK: block = recv.stream_out(cls=Block.PyBlock) ## debug print print("received block: \n%s" % str(block)) inv = net.PyInv(net.MsgType.MSG_BLOCK, block.get_hash()) node_from.add_inventory_known(inv) if blockaction.process_block(node_from, block): ctx.dictAlreadyAskedFor.pop(inv, None) elif command == base.COMMAND_GETADDR: node_from.list_addr_to_send = list() ## need to expand the time range if not enough found since = timeutil.get_adjusted_time( ) - cfg.COMMAND_GETADDR_SPAN_TIME # in the last hour with ctx.dictAddressesLock: for addr in iter(ctx.dictAddresses.itervalues()): if ctx.fShutdown: return if addr.time > since: node_from.list_addr_to_send.append(addr) elif command == base.COMMAND_CHECKORDER: hash_reply = recv.stream_out(out_type="uint256") order = recv.stream_out(cls=Block.PyWalletTx) # todo: we have a chance to check the order here # # Keep giving the same key to the same ip until they use it if node_from.addr.ip is not dictReuseKey: dictReuseKey[node_from.addr.ip] = keyaction.generate_new_key( ) # generate pubkey : str # Send back approval of order and pubkey to use script_pubkey = script.PyScript() script_pubkey.extend(dictReuseKey[node_from.addr.ip]).append( script.OpCodeType.OP_CHECKSIG) node_from.push_message(base.COMMAND_REPLY, (hash_reply, "uint256"), (0, "int"), (script_pubkey.get_str(), "str")) elif command == base.COMMAND_SUBMITORDER: hash_reply = recv.stream_out(out_type="uint256") wtx_new = recv.stream_out(cls=Block.PyWalletTx) # Broadcast if not wtx_new.accept_wallet_transaction(): node_from.push_message(base.COMMAND_REPLY, (hash_reply, "uint256"), (1, "int")) print( "submitorder AcceptWalletTransaction() failed, returning error 1" ) return False wtx_new.time_received_is_tx_time = 1 Block.add_to_wallet(wtx_new) wtx_new.relay_wallet_transaction() dictReuseKey.pop(node_from.addr.ip, None) # Send back confirmation node_from.push_message(base.COMMAND_REPLY, (hash_reply, "uint256"), (0, "int")) elif command == base.COMMAND_REPLY: hash_reply = recv.stream_out(out_type="uint256") # code_reply = recv.stream_out(out_type="int") with node_from.dict_requests_lock: tracker = node_from.dict_requests.get(hash_reply, None) if tracker is not None: tracker.func(tracker.param, recv) # recv contain code_reply(0 or 1) else: # Ignore unknown commands for extensibility print("ProcessMessage(%s) : Ignored unknown message" % command) if len(recv) != 0: print("ProcessMessage(%s) : %d extra bytes" % (command, len(recv))) return True
def test_txn(): txdb = Tx.PyTxDB(f_txn=True) txdb.txn_begin() print '123' txdb.txn_commit() pass
def bitcoin_miner(t): """ :param t: :type t: ExitedThread :return: """ print "Miner started" # TODO add thread priority THREAD_PRIORITY_LOWEST key = Key.PyKey() key.make_new_key() extra_nonce = 0 while ctx.fGenerateCoins: timeutil.sleep_msec(50) # 50 ms t.check_self_shutdown() if t.exit: break # while len(ctx.listNodes) == 0: # timeutil.sleep_msec(1000) # t.check_self_shutdown() # if t.exit: # return True transactions_updated_last = ctx.transactionsUpdated index_prev = ctx.indexBest bits = Block.get_next_work_required(index_prev) # create coinbase tx tx_new = Tx.PyTransaction() tx_in = Tx.PyTxIn() tx_in.prev_out.set_null() extra_nonce += 1 tx_in.script_sig.append(bits).append(extra_nonce) tx_new.l_in.append(tx_in) tx_out = Tx.PyTxOut() tx_out.script_pubkey.extend(key.get_pubkey()).append( Script.OpCodeType.OP_CHECKSIG) tx_new.l_out.append(tx_out) # create new block block = Block.PyBlock() # Add our coinbase tx as first transaction block.l_tx.append(tx_new) # Collect the latest transactions into the block fees = 0 with ctx.mainLock: with ctx.dictTransactionsLock: txdb = Tx.PyTxDB("r") test_pool = dict() # map<uint256, PyTxIndex> flag_already_added = [False] * len(ctx.dictTransactions) found_something = True block_size = 0 while found_something and block_size < cfg.MAX_SIZE / 2: # block_size < 2MB/2 = 1MB found_something = False n = 0 for tx_hash, tx in ctx.dictTransactions.iteritems(): if flag_already_added[n]: continue if tx.is_coinbase() or not tx.is_final(): continue # Transaction fee requirements, mainly only needed for flood control # Under 10K (about 80 inputs) is free for first 100 transactions # Base rate is 0.01 per KB min_fee = tx.get_min_fee( len(block.l_tx) < 100) # 100 个交易内的打折,之后的不打折 tmp_test_pool = copy.deepcopy( test_pool) # 防止下面执行出错对test_pool产生干扰 ret = tx.connect_inputs(txdb, tmp_test_pool, Tx.PyDiskTxPos(1, 1, 1), 0, False, True, min_fee) if ret is None: continue fees += ret # 累积交易费 test_pool = tmp_test_pool block.l_tx.append(tx) block_size += tx.serialize_size( serialize.SerType.SER_NETWORK) flag_already_added[n] = True found_something = True # 这是为了跳出外层 while n += 1 # end for pass pass # end while txdb.close() pass # end critical_block pass block.bits = bits block.l_tx[0].l_out[0].value = block.get_block_value(fees) print("\n\nRunning Miner with %d transactions in block" % len(block.l_tx)) # Prebuild hash buffer class Unnamed1(serialize.Serializable): class Unnamed2(serialize.Serializable): def __init__(self): self.version = 0 self.hash_prev_block = 0 self.hash_merkle_root = 0 self.time = 0 self.bits = 0 self.nonce = 0 def serialize(self, nType=0, nVersion=cfg.VERSION): s = b'' s += serialize.ser_int(self.version) s += serialize.ser_uint256(self.hash_prev_block) s += serialize.ser_uint256(self.hash_merkle_root) s += serialize.ser_uint(self.time) s += serialize.ser_uint(self.bits) s += serialize.ser_uint(self.nonce) return s def __init__(self): self.block = Unnamed1.Unnamed2() self.padding0 = ['\x00'] * 64 self.hash1 = 0 self.padding1 = ['\x00'] * 64 tmp = Unnamed1() tmp.block.version = block.version tmp.block.hash_prev_block = block.hash_prev_block = ( index_prev.get_block_hash() if index_prev else 0) tmp.block.hash_merkle_root = block.hash_merkle_root = block.build_merkle_tree( ) tmp.block.time = block.time = max( (index_prev.get_median_time_past() + 1 if index_prev else 0), timeutil.get_adjusted_time()) tmp.block.bits = block.bits = bits # difficulty tmp.block.nonce = block.nonce = 1 # 从1 开始计算 # blocks0 = format_hash_blocks(tmp.block.serialize(), tmp.padding0) # blocks1 = format_hash_blocks(serialize.ser_uint256(tmp.hash1), tmp.padding1) # search start = timeutil.get_time() block_hash = 0 hash_target = BN.PyBigNum.set_compact(block.bits).get_uint256() while True: if t.exit: break # use local sha256 block_hash = cryptoutil.Hash(tmp.block.serialize()) if block_hash <= hash_target: block.nonce = tmp.block.nonce assert block_hash == block.get_hash() # debug print print("Miner:") print("proof-of-work found \n hash: %s \ntarget: %s\n" % (serialize.hexser_uint256(block_hash), serialize.hexser_uint256(hash_target))) print str(block) # TODO setthreadpriority THREAD_PRIORITY_NORMAL with ctx.mainLock: # save key kaction.add_key(key) key.make_new_key() # Process this block the same as if we had received it from another node if not blkaction.process_block(None, block): print( "ERROR in CoinMiner, ProcessBlock, block not accepted" ) else: print("miner a block, waiting for relay") # TODO ADD THREAD_PRIORITY_LOWEST timeutil.sleep_msec(500) break # Update nTime every few seconds tmp.block.nonce += 1 if tmp.block.nonce & 0x3FFFF == 0: # checkforshutdown if tmp.block.nonce == 0: break if id(index_prev) != id(ctx.indexBest): break if ctx.transactionsUpdated != transactions_updated_last and ( timeutil.get_time() - start > 60): break if not ctx.fGenerateCoins: break tmp.block.time = block.time = max( (index_prev.get_median_time_past() + 1), timeutil.get_adjusted_time()) pass # end nonce loop pass # end whole loop return True
def create_transaction(script_pubkey, value, wtx_new, fee_required=None): """ 根据指向自己的PyWalletTx的Out填充wtx_new的 PyTxIn, value指明转账费, 将会验证交易费,合法性,\n 并自动收集满足条件的交易, 并对 wtx_new 的 PyTxIn进行签名\n :param script_pubkey: 填充 wtx_new PyTxOut 的 pubkey_script :param value: 转账的数目 :param wtx_new: 被填充的交易 :type wtx_new: Block.PyWalletTx :return: None 或 需要支付的交易费 fee """ if fee_required is None: fee_required = list() if len(fee_required) == 0: fee_required.append(0) else: fee_required[0] = 0 with ctx.mainLock: with Tx.PyTxDB("r") as txdb: with ctx.dictWalletLock: # txdb = Tx.PyTxDB("r") fee = ctx.transactionFee # 全局配置的交易费 while True: del wtx_new.l_in[:] del wtx_new.l_out[:] if value < 0: return None value_out = value # 此时的value_out 代表真正想要转出的钱 value += fee # 此时 value 包含手续费 # Choose coins to use set_coins = select_coins(value) if set_coins is None: return None set_coins = tuple(set_coins) value_in = 0 # 获取自己能给出的全部钱总和 for coin in set_coins: # PyWalletTx value_in += coin.get_credit() # Fill vout[0] to the payee wtx_new.l_out.append(Tx.PyTxOut(value_out, script_pubkey)) # Fill vout[1] back to self with any change if value_in > value: # value 包含了手续费 # Use the same key as one of the coins tx_first = set_coins[0] pubkey = b'' for txout in tx_first.l_out: if txout.is_mine(): pubkey = Script.extract_pubkey(txout.script_pubkey, True) if pubkey is not None: break if len(pubkey) == 0: return None # Fill vout[1] to ourself my_script_pubkey = Script.PyScript() my_script_pubkey.extend(pubkey).append(Script.OpCodeType.OP_CHECKSIG) wtx_new.l_out.append(Tx.PyTxOut(value_in - value, my_script_pubkey)) # fill vin for coin in set_coins: for index, out in enumerate(coin.l_out): if out.is_mine(): wtx_new.l_in.append(Tx.PyTxIn(Tx.PyOutPoint(coin.get_hash(), index))) # no sign # Sign nin = 0 for coin in set_coins: for out in coin.l_out: if out.is_mine(): ret = Script.sign_signature(coin, wtx_new, nin) if ret is False: print ("sign failed for txin index: %d: to wtx_new: %s" % (nin, str(wtx_new))) return None nin += 1 # Check that enough fee is included real_fee = wtx_new.get_min_fee(True) # 如果交易费小于最小的交易费,那么就要调整并重新运算 if fee < real_fee: fee = real_fee fee_required[0] = fee continue wtx_new.add_supporting_transactions(txdb) wtx_new.time_received_is_tx_time = 1 # 该函数只会由生产tx的节点调用,这个属性的意义就代表的这个wtx是自己产生的还是别人 break return fee