def test_block(): timestamp = "The Times 22/Mar/2017 Chancellor on brink of second bailout for banks" tx_new = Tx.PyTransaction() txin = Tx.PyTxIn() init_nbits = 0x1f00ffff sig = Script.PyScript().append(init_nbits).append_num(4).extend(timestamp) # script << nbits << extra_nonce txin.script_sig = sig txout = Tx.PyTxOut() txout.value = 50 * cfg.COIN txout.script_pubkey = Script.PyScript().extend(binascii.unhexlify(cfg.GENESIS_PUBKEY)) \ .append(Script.OpCodeType.OP_CHECKSIG) tx_new.l_in.append(txin) tx_new.l_out.append(txout) block = Block.PyBlock() block.l_tx.append(tx_new) block.hash_prev_block = 0 block.hash_merkle_root = block.build_merkle_tree() block.version = 1 block.time = 1490092537 block.bits = init_nbits block.nonce = 87401 print block.get_hash('hex')
def copytx(): timestamp = "The Times 22/Mar/2017 Chancellor on brink of second bailout for banks" tx_new = Tx.PyTransaction() txin = Tx.PyTxIn() init_nbits = 0x1f00ffff sig = Script.PyScript().append(init_nbits).append_num(4).extend(timestamp) # script << nbits << extra_nonce txin.script_sig = sig txout = Tx.PyTxOut() txout.value = 50 * cfg.COIN # scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; Hash160(pubkey) # txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG; # txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; txout.script_pubkey = Script.PyScript().extend(binascii.unhexlify(cfg.GENESIS_PUBKEY)) \ .append(Script.OpCodeType.OP_CHECKSIG) tx_new.l_in.append(txin) tx_new.l_out.append(txout) tx = copy.deepcopy(tx_new) l1 = list() # l1.append(txout) # l1.append(txin) # copy.deepcopy(l1) # s = copy.deepcopy(txout.script_pubkey) # print txout.script_pubkey # print s pass
def load_blockindex(): # Load block index txdb = Block.PyTxExtDB("cr") if not txdb.load_blockindex(): txdb.close() return False txdb.close() # Init with genesis block if not ctx.dictBlockIndex: # dictBlockIndex is empty() if not cfg.ALLOW_NEW: return False # Genesis block ! timestamp = "The Times 22/Mar/2017 Chancellor on brink of second bailout for banks" tx_new = Tx.PyTransaction() txin = Tx.PyTxIn() init_nbits = 0x1f00ffff sig = Script.PyScript().append(init_nbits).append_num(4).extend( timestamp) # script << nbits << extra_nonce txin.script_sig = sig txout = Tx.PyTxOut() txout.value = 50 * cfg.COIN # scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; Hash160(pubkey) # txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG; # txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; txout.script_pubkey = Script.PyScript().extend(binascii.unhexlify(cfg.GENESIS_PUBKEY)) \ .append(Script.OpCodeType.OP_CHECKSIG) tx_new.l_in.append(txin) tx_new.l_out.append(txout) block = Block.PyBlock() block.l_tx.append(tx_new) block.hash_prev_block = 0 block.hash_merkle_root = block.build_merkle_tree() block.version = 1 block.time = 1490092537 block.bits = init_nbits block.nonce = 45164 assert block.get_hash( ) == ctx.hashGenesisBlock, "genesis block hash not equal to block.get_hash()" # start new block file ret = block.write_to_disk(not ctx.fClient) if ret is None: print("LoadBlockIndex() : writing genesis block to disk failed") return False file_index = ret[0] block_pos = ret[1] if not block.add_to_blockindex(file_index, block_pos): print("LoadBlockIndex() : genesis block not accepted") return False load_genesis_tx(tx_new, block) pass # end if return True
def genesis_block(): timestamp = "The Times 22/Mar/2017 Chancellor on brink of second bailout for banks" tx_new = Tx.PyTransaction() txin = Tx.PyTxIn() init_nbits = 0x1f00ffff sig = Script.PyScript().append(init_nbits).append_num(4).extend(timestamp) # script << nbits << extra_nonce txin.script_sig = sig txout = Tx.PyTxOut() txout.value = 50 * cfg.COIN # scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; Hash160(pubkey) # txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG; # txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; txout.script_pubkey = Script.PyScript().extend(binascii.unhexlify(cfg.GENESIS_PUBKEY)) \ .append(Script.OpCodeType.OP_CHECKSIG) tx_new.l_in.append(txin) tx_new.l_out.append(txout) block = Block.PyBlock() block.l_tx.append(tx_new) block.hash_prev_block = 0 block.hash_merkle_root = block.build_merkle_tree() block.version = 1 block.time = 1490092537 # block.bits = 0x2000ffff # block.bits = init_nbits # nonce:45164 hash:2e72d19b7558bd6ec869e5601c3613cc7a6b3f24118773d7aaaa3c285493fdfc # block.bits = 0x1e00ffff # nonce:xxx (cast almost 5 min) block.nonce = 0 hash_target = BN.PyBigNum.set_compact(block.bits).get_uint256() target_hex = serialize.hexser_uint256(hash_target) # target_hex = long(hash_target) time1 = timeutil.get_time() print 'start time:', time1 while True: block_hash = cryptoutil.Hash(block.serialize()) print 'nonce:', block.nonce print 'now hash:' print serialize.hexser_uint256(block_hash) # print long(block_hash) print 'target' print target_hex if block_hash <= hash_target: print 'current nonce:' print block.nonce print binascii.hexlify(serialize.ser_uint256(block.get_hash())) print block.get_hash('hex') print long(hash_target) break block.nonce += 1 time2 = timeutil.get_time() print 'end time:', time2 diff = time2 - time1 print("%d:%d" % (diff / 60, diff % 60))
def deserialize(self, f, nType=0, nVersion=cfg.VERSION): f = wrap_to_StringIO(f) self.prev_out = PyOutPoint() self.prev_out.deserialize(f) self.script_sig = Script.PyScript(deser_str(f)) self.sequence = deser_uint(f) return self
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 __init__(self, prev_out=None, script_sig=None, sequence=0xffffffff): self.prev_out = PyOutPoint() if prev_out is None else prev_out self.script_sig = Script.PyScript() if script_sig is None else script_sig self.sequence = sequence
def set_null(self): self.value = -1 # amount int64 self.script_pubkey = Script.PyScript() # equal to PyScript
def deserialize(self, f, nType=0, nVersion=cfg.VERSION): f = wrap_to_StringIO(f) self.value = deser_int64(f) self.script_pubkey = Script.PyScript(deser_str(f)) return self
def __init__(self, value_out=-1, script_pubkey=None): self.value = value_out # amount int64 self.script_pubkey = Script.PyScript() if script_pubkey is None else script_pubkey # PyScript lock script
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