def getInitialUser(): private_key = ed25519.Ed25519PrivateKey.from_private_bytes( bytes.fromhex( "1d82897e5881368cac9eb99126cdfca1e0317629dbeaa7280484c5dae81e932b") ) public_key = ed25519.Ed25519PublicKey.from_public_bytes( bytes.fromhex( "75efa6f1fdf1393a5ea815b2b3690293d079df187944f22ec79f3380ef7bd743") ) txns = [ Transaction.build_signed_txn( "75efa6f1fdf1393a5ea815b2b3690293d079df187944f22ec79f3380ef7bd743", [], [ OutFlow( 10000, "75efa6f1fdf1393a5ea815b2b3690293d079df187944f22ec79f3380ef7bd743" ) ], "1d82897e5881368cac9eb99126cdfca1e0317629dbeaa7280484c5dae81e932b") ] # Note that we need two hexadecimal digits for the bytes.fromhex( str ) method to work, # hence we include two zeros block_obj = Block("00", txns, 0) success = False while not success: magic_num = os.urandom(32).hex() block_obj.magic_num = magic_num if int(block_obj.get_hash(), 16) & 0xFFFF == 0xCCCC: success = True print(json.dumps(block_obj.serialize()))
def test_block(self): args = (0, "0", int(time.time()), "test") nonce = 0 target = "f" * 64 hash = Block.calculate_hash(*args, nonce, target) b = Block(*args, nonce=nonce, target=target, hash=hash) self.assertSerializable(Block, b, globals()) self.assertTrue(b.valid) b.hash = "aaa" self.assertFalse(b.valid)
def mine(self): """ Looks in redis for transactions and mines them to find the answer to the puzzle """ print("Mining") prev_hash = self.r.get(PREV_HASH_KEY) if prev_hash: prev_hash = prev_hash.decode('utf-8') block = Block(prev_hash) # wait to fill the block with transactions while not block.full(): # in between mining if self.stop_mining(): print("Someone mined the coins") l = len(block.transactions) left = TRANSACTIONS_IN_BLOCK - l for _ in range(left): self.r.blpop(TRANSACTION_QUEUE_KEY) return None print("Searching for transactions to fill the block") # blocking pop from transaction key transaction = Transaction.from_redis( self.r, json.loads( self.r.blpop(TRANSACTION_QUEUE_KEY)[1].decode('utf-8'))) print("found a transaction, adding it to block") block.add_transaction(transaction) # create a new transaction that creates a lazycoin and gives it to the user print("Block is full, now add a create transaction") print("Prev hash = ", prev_hash) create = Transaction( prev_hash=prev_hash, transaction_type='CREATE', sender=self.user.pub, receiver=self.user.pub, ) # sign this transaction and add the signature to the transaction print("signing transaction") msg, sign = self.user.sign(create) create.add_signature(sign) print("adding transaction") block.add_transaction(create) print("finding nonce") nonce = self.solve_puzzle(block) block.add_nonce(nonce) print("block done") if self.stop_mining(): print("stopping mining") return None return block
def __mining(self) -> Optional[Block]: """挖矿""" trans_list = self.__get_mining_trans() with FullBlockChain.safe_use_blockchain() as blc: block = Block(blc.get_height() + 1, blc.get_top_hash()) # 计算总交易费 fee = Btc("0") for trans in trans_list: fee += blc.compute_transaction_fee(trans) block.add_transaction(trans) # 添加交易到block中 # 加上矿工奖励 fee += block.get_now_ming_btcs() # 构造创块交易 head_trans = Transaction() head_trans.add_output(TransOutput(address=self.address, btcs=fee)) block.set_head_transaction(head_trans) # 正式开始挖矿 while not block.veri_hash(): if self.mine_flag: block.randnum += MINING_ADD_NUM block.timestap = time.time() else: # 中止挖矿(失败了) self.add_trans(*trans_list) # 把交易放回交易池 return None return block
def test_block_message(self): message = messages.msg_block() cblock = CBlock() message.block = cblock block = Block(None, BlockOrigin.private) block.cached_hash = message.block.GetHash() self.chain.blocks = {block.hash(): block} self.networking.block_message(self.private_connection, message) self.assertEqual(self.chain.blocks[block.hash()].cblock, cblock)
def test_block_message_remove_from_blocks_in_flight(self): message = messages.msg_block() cblock = CBlock() message.block = cblock block = Block(None, BlockOrigin.private) block.cached_hash = message.block.GetHash() self.chain.blocks = {block.hash(): block} self.networking.blocks_in_flight = {block.hash(): 'in_flight'} self.networking.block_message(self.private_connection, message) self.assertEqual(len(self.networking.blocks_in_flight), 0)
def test_block_message_two_times(self): message = messages.msg_block() cblock1 = CBlock(nNonce=1) cblock2 = CBlock(nNonce=2) message.block = cblock1 block = Block(None, BlockOrigin.private) block.cached_hash = message.block.GetHash() self.chain.blocks = {block.hash(): block} self.networking.block_message(self.private_connection, message) message.block = cblock2 self.networking.block_message(self.private_connection, message)
def init(): # 删除旧文件 if os.path.isfile(STORE_BLC_FILE_PATH): os.remove(STORE_BLC_FILE_PATH) if os.path.isfile(STORE_KEYS_FILE_PATH): os.remove(STORE_KEYS_FILE_PATH) # 打开N服务和B服务 NetworkRouting.get_instance().start_server() FullBlockChain.get_instance().start_server() # 添加创世区块 keys = [UserKey() for i in range(10)] for key in keys: Wallet.get_instance().add_key(key) Miner.get_instance().set_wallet_address(keys[0].get_address()) t = Transaction() for key in keys: t.add_output(TransOutput(Btc("1000"), key.get_address())) block = Block(1) block.add_transaction(t) head_trans = Transaction() head_trans.add_output(TransOutput(Btc(MINING_BTCS), keys[0].get_address())) block.set_head_transaction(head_trans) block.find_randnum() FullBlockChain.get_instance().add_first_block(block) Wallet.get_instance().write_keys_to_file()
def get_block(self, index: int) -> Block: """取出指定索引块""" with self.__auto_commit() as cusor: fet = cusor.execute( f"select block from blockchain where \"index\"={index}") b = fet.fetchone()[0] return Block.load(b)
def test_adopt_two_blocks_lead_public(self): third_block_chain_b = Block(CBlock(), BlockOrigin.public) third_block_chain_b.height = 3 third_block_chain_b.prevBlock = self.second_block_chain_b third_block_chain_b.cached_hash = '3b' self.executor.execute(Action.adopt, self.first_block_chain_a, third_block_chain_b) self.assertTrue(self.networking.send_inv.called) blocks = [block.hash() for block in self.networking.send_inv.call_args[0][0]] self.assertEqual(len(blocks), 3) self.assertTrue('1b' in blocks) self.assertTrue('2b' in blocks) self.assertTrue('3b' in blocks)
def test_override_two_blocks_lead_private(self): third_block_chain_a = Block(CBlock(), BlockOrigin.private) third_block_chain_a.height = 3 third_block_chain_a.prevBlock = self.second_block_chain_a third_block_chain_a.cached_hash = '3a' self.executor.execute(Action.override, third_block_chain_a, self.first_block_chain_b) self.assertTrue(self.networking.send_inv.called) blocks = [block.hash() for block in self.networking.send_inv.call_args[0][0]] self.assertEqual(len(blocks), 3) self.assertTrue('1a' in blocks) self.assertTrue('2a' in blocks) self.assertTrue('1b' in blocks)
def __init__(self) -> None: self.trans_cache = MyQueue() # 交易池 self.trans_num = MAX_USER_TRANSACTION_NUMBER # 一个区块打包多少个交易 self.address = "" # 获取收益的地址 self.server_flag = True self.mine_flag = True self.trans_later = Transaction() self.block_later = Block()
def test_getdata_message_with_block(self): cblock = CBlock() block = Block(cblock, BlockOrigin.private) block.cblock = cblock message = messages.msg_getdata() cInv = CInv() cInv.type = networking.inv_typemap['Block'] cInv.hash = cblock.GetHash() message.inv = [cInv] self.chain.blocks = {cblock.GetHash(): block} self.networking.getdata_message(self.public_connection1, message) self.assertTrue(self.public_connection1.send.called) self.assertEqual(self.public_connection1.send.call_args[0][0], 'block') self.assertEqual(self.public_connection1.send.call_args[0][1].block, cblock)
def test_block_message_deferred_requests(self): message = messages.msg_block() cblock = CBlock() hash_ = cblock.GetHash() message.block = cblock block = Block(None, BlockOrigin.private) block.cached_hash = hash_ self.networking.deferred_block_requests = \ {hash_: [self.private_connection.host[0], self.public_connection2.host[0]]} self.networking.send_block = MagicMock() self.networking.block_message(self.public_connection1, message) self.assertEqual(len(self.networking.deferred_block_requests), 0) self.assertEqual(self.networking.send_block.call_count, 2) self.assertEqual(self.networking.send_block.call_args[0][1], cblock)
def verify_new_block(cls, block: Block) -> bool: """验证一个新块""" if not cls.verify_block_depth(block): return False # pre_hash的值要正确 if block.get_prehash() != BlockChain.get_instance().get_top_block( ).get_hash(): return False # 验证每笔交易的有效性 inputs = [] for trans in block.get_user_transactions(): if not cls.verify_new_transaction(trans): return False inputs.extend(trans.get_inputs()) # 不同的交易不能有相同的输入 if len(set(inputs)) != len(inputs): return False return True
def run(): """接收区块,广播区块线程""" while self.server_flag: node, msg = B_mailbox.get() if msg.type == "PUT": if msg.command == "BLOCK": # 添加新块,广播新块 block = Block.load(msg.data) if self.add_new_block(block): NetworkRouting.get_instance().broad_a_msg(msg) elif msg.type == "GET": pass # TODO
def verify_block_depth(cls, block: Block) -> bool: """深入验证区块(包括区块中的交易)""" if not cls.verify_block(block): return False # 验证用户的交易 for trans in block.get_user_transactions(): if not cls.verify_transaction(trans): return False # 验证第一笔交易 trans = block.get_head_transaction() # 计算交易费 fee = BlockChain.get_instance().compute_block_fee(block) # 计算矿工奖励 mini_fee = trans.compute_outputs_btcs() - fee # 计算这个区块时的矿工奖励 mini_btcs = block.get_now_ming_btcs() # 验证矿工奖励合法性 if mini_fee != mini_btcs: return False return True
def test_getdata_message_with_two_blocks(self): cblock1 = CBlock() block1 = Block(cblock1, BlockOrigin.private) block1.cblock = cblock1 cInv1 = CInv() cInv1.type = networking.inv_typemap['Block'] cInv1.hash = cblock1.GetHash() cblock2 = CBlock() block2 = Block(cblock2, BlockOrigin.private) block2.cblock = cblock2 cInv2 = CInv() cInv2.type = networking.inv_typemap['Block'] cInv2.hash = cblock2.GetHash() message = messages.msg_getdata() message.inv = [cInv1, cInv2] self.chain.blocks = { cblock1.GetHash(): block1, cblock2.GetHash(): block2 } self.networking.getdata_message(self.public_connection1, message) self.assertTrue(self.public_connection1.send.called) self.assertEqual(self.public_connection1.send.call_count, 2)
def setUp(self): self.networking = MagicMock() self.executor = Executor(self.networking) self.first_block_chain_b = Block(CBlock(), BlockOrigin.public) self.first_block_chain_b.height = 1 self.first_block_chain_b.prevBlock = test_util.genesis_block self.first_block_chain_b.cached_hash = '1b' self.second_block_chain_b = Block(CBlock(), BlockOrigin.public) self.second_block_chain_b.height = 2 self.second_block_chain_b.prevBlock = self.first_block_chain_b self.second_block_chain_b.cached_hash = '2b' self.first_block_chain_a = Block(CBlock(), BlockOrigin.private) self.first_block_chain_a.height = 1 self.first_block_chain_a.prevBlock = test_util.genesis_block self.first_block_chain_a.cached_hash = '1a' self.second_block_chain_a = Block(CBlock(), BlockOrigin.private) self.second_block_chain_a.height = 2 self.second_block_chain_a.prevBlock = self.first_block_chain_a self.second_block_chain_a.cached_hash = '2a'
def test_match_lead_public(self): private_tip = Block(CBlock(), None) private_tip.height = 1 public_tip = Block(CBlock(), None) public_tip.height = 2 with self.assertRaisesRegexp(ActionException, "private tip.*must >= then public tip.*match.*"): self.executor.execute(Action.match, private_tip, public_tip)
async def proof_of_work(self): nonce = 0 tx = None while True: h = sha256() difficulty = consensus.get_difficulty(self.chain_mgr.chain.chain) target = consensus.STANDARD_TARGET / difficulty prev_block = self.chain_mgr.chain.chain[-1] if not tx: # Poll transaction updates tx = self.pop_transaction() block = Block( **{ 'index': prev_block.index + 1, 'timestamp': time.time(), 'data': { 'transactions': [tx.__dict__] } if tx else 'mining test', 'prev_hash': prev_block.hash, 'difficulty': difficulty, }) logger.info('Tx: {}'.format(tx)) h.update('{}{}{}'.format(prev_block, block, nonce).encode('utf8')) hash_value = int(h.hexdigest(), 16) logger.info( 'Hashed block{}@ difficulty={} nonce={} result={}'.format( block.index, difficulty, nonce, h.hexdigest())) if hash_value < target: logger.info( 'solution found! {} @ target: {}, index: {}'.format( nonce, target, block.index)) block.nonce = nonce return block await asyncio.sleep(1) # 1h/s nonce += 1
def test_adopt_same_height(self): private_tip = Block(CBlock(), None) private_tip.height = 2 public_tip = Block(CBlock(), None) public_tip.height = 2 with self.assertRaisesRegexp(ActionException, "public tip.*must > then private tip.*adopt.*"): self.executor.execute(Action.adopt, private_tip, public_tip)
def test_override_same_height(self): private_tip = Block(CBlock(), None) private_tip.height = 2 public_tip = Block(CBlock(), None) public_tip.height = 2 with self.assertRaisesRegexp(ActionException, "private tip.*must > then public tip.*override.*"): self.executor.execute(Action.override, private_tip, public_tip)
def test_insert_block_initializing_false(self): prevBlock = Block(CBlock(), BlockOrigin.private) prevBlock.cached_hash = 'hash2' prevBlock.height = 45 block = Block(CBlock(), BlockOrigin.private) block.cached_hash = 'hash1' self.chain.tips = [prevBlock] self.chain.initializing = False self.chain.insert_block(prevBlock, block) retrieved_block = self.chain.tips[0] self.assertEqual(retrieved_block, block) self.assertEqual(retrieved_block.transfer_allowed, False)
def handle_receive_latest_block(self, block: dict) -> None: peer_block = Block.deserialize(block) latest_block = self.blockchain.latest_block is_added = self.blockchain.add_block(peer_block) if is_added: self.server.broadcast_message( Message.send_latest_block(peer_block)) elif latest_block.index < peer_block.index: # peer is longer, ask for blockchain logger.debug("Having no latest block. Asking for blockchain") self.server.broadcast_message(Message.get_blockchain()) else: # I'm on the edge! pass self.transport.close()
def recv_broad_transaction(): """接收交易、广播交易的进程""" while self.server_flag: # 阻塞在取trans的地方 node, msg = M_mailbox.get() if msg.type == "PUT": if msg.command == "TRANS": trans = Transaction.load(msg.data) if trans != self.trans_later and self.add_trans(trans): self.trans_later = trans NetworkRouting.get_instance().broad_a_msg( msg) # 广播交易 elif msg.command == "BLOCK": # 其它进程先挖到,暂停挖矿 block = Block.load(msg.data) if self.block_later != block and Verify.verify_new_block( block) and FullBlockChain.get_instance( ).get_top_hash() == block.get_hash(): self.accept_block(block)
def test_getdata_message_cblock_not_available(self): cblock = CBlock() hash_ = cblock.GetHash() block = Block(cblock, BlockOrigin.private) message = messages.msg_getdata() cInv = CInv() cInv.type = networking.inv_typemap['Block'] cInv.hash = hash_ message.inv = [cInv] self.chain.blocks = {hash_: block} self.networking.deferred_block_requests = {} self.networking.getdata_message(self.public_connection1, message) self.assertFalse(self.public_connection1.called) self.assertIn(hash_, self.networking.deferred_block_requests) self.assertIn(self.public_connection1.host[0], self.networking.deferred_block_requests[hash_])
def main(): blockchain = Blockchain() database = ["hello", "goodbye", "test", "DATA here", "test2"] num = 0 for data in database: num += 1 blockchain.mine(Block(num, data=data)) for block in blockchain.chain: print(block) print(blockchain.isValid()) # i try to change data in blck number 2 without valid nonce blockchain.chain[2].data = "NEW DATA" blockchain.mine(blockchain.chain[2]) print(blockchain.isValid())
def test_send_inv_public_blocks(self): block1 = Block(CBlock(), BlockOrigin.public) block1.cached_hash = 'hash1' block2 = Block(CBlock(), BlockOrigin.public) block2.cached_hash = 'hash2' self.networking.send_inv([block1, block2]) self.assertFalse(self.public_connection1.send.called) self.assertFalse(self.public_connection2.send.called) self.assertTrue(self.private_connection.send.called) inv = self.private_connection.send.call_args[0][1].inv self.assertEqual(len(inv), 2)
def test_insert_block(self): prevBlock = Block(CBlock(), BlockOrigin.private) prevBlock.cached_hash = 'hash2' prevBlock.height = 45 block = Block(CBlock(), BlockOrigin.private) block.cached_hash = 'hash1' self.chain.tips = [prevBlock] self.chain.insert_block(prevBlock, block) self.assertFalse(prevBlock in self.chain.tips) self.assertEqual(len(self.chain.tips), 1) retrieved_block = self.chain.tips[0] self.assertEqual(retrieved_block, block) self.assertEqual(retrieved_block.prevBlock, prevBlock) self.assertEqual(retrieved_block.height, 46)