def get_example_genesis_block(): return Block.deserialize(computer( """000000000000000000000000000000000000000000000000000000000000000000008278968af4bd613aa24a5ccd5280211b3101e3""" """ff62621bb11500509d1bbe2a956046240b0100000000000000000000000000000000000000000000000000000000000000000000d7""" """38f2c472180cb401f650b12be96ec25bfd9b4e9908c6c9089d9bf26401646f87000000000000000000000000000000000000000000""" """0000000000000000000000077a14cfbe21d47f367f23f9a464c765541b1b07bef9f5a95901e0bffe3a1a2f01000100000000000000""" """000000000000000000000000000000000000000000000000000000000001000000000001000000012a05f200027878787878787878""" """7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878""" """787878"""))
def handle_mined_block(self, block: Block) -> None: self.coinstate = self.coinstate.add_block(block, int(time())) with open(Path('chain') / block_filename(block), 'wb') as f: f.write(block.serialize()) self.send_message("found_block", block_filename(block)) self.send_message("balance", self.get_balance()) self.thread.local_peer.chain_manager.set_coinstate(self.coinstate) self.thread.local_peer.network_manager.broadcast_block(block)
def _read_chain_from_disk(max_height): coinstate = CoinState.zero() for file_path in sorted(CHAIN_TESTDATA_PATH.iterdir()): height = int(file_path.name.split("-")[0]) if height > max_height: return coinstate block = Block.stream_deserialize(open(file_path, 'rb')) coinstate = coinstate.add_block_no_validation(block) return coinstate
def read_chain_from_disk(): print("Reading chain from disk") coinstate = CoinState.zero() for filename in sorted(os.listdir('chain')): height = int(filename.split("-")[0]) if height % 1000 == 0: print(filename) block = Block.stream_deserialize(open(Path('chain') / filename, 'rb')) coinstate = coinstate.add_block_no_validation(block) return coinstate
def handle_scrypt_output_message(self, miner_id: int, data: bytes) -> None: summary_hash: bytes = data self.increment_hash_counter() summary, current_height, transactions = self.mining_args[miner_id] evidence = construct_pow_evidence_after_scrypt(summary_hash, self.coinstate, summary, current_height, transactions) block = Block(BlockHeader(summary, evidence), transactions) if block.hash() >= block.target: # we didn't mine the block return self.network_thread.local_peer.chain_manager.set_coinstate( self.coinstate) self.network_thread.local_peer.network_manager.broadcast_block(block) self.coinstate = self.coinstate.add_block(block, int(time())) # Originally there was a disk write in this spot. During testing of the chain.cache changes, # it was found there is a race condition between the mining thread and the networking thread. # Better to skip the write here and just let the networking thread do it. print(f"miner {miner_id} found block: {block_filename(block)}") # get new public key for miner self.public_key = self.wallet.get_annotated_public_key( "reserved for potentially mined block") save_wallet(self.wallet) self.balance = self.wallet.get_balance( self.coinstate) / Decimal(SASHIMI_PER_COIN)
def _read_chain_from_disk(max_height): # the requirement to run these tests from an environment that has access to the real blockchain is hard-coded (for # now) coinstate = CoinState.zero() for filename in sorted(os.listdir('chain')): height = int(filename.split("-")[0]) if height > max_height: return coinstate block = Block.stream_deserialize(open(Path('chain') / filename, 'rb')) coinstate = coinstate.add_block_no_validation(block) return coinstate
def read_chain_from_disk(): print("Reading chain from disk") coinstate = CoinState.zero() for filename in sorted(os.listdir('chain')): height = int(filename.split("-")[0]) if height % 1000 == 0: print(filename) try: block = Block.stream_deserialize(open(Path('chain') / filename, 'rb')) except Exception as e: raise Exception("Corrupted block on disk: %s" % filename) from e coinstate = coinstate.add_block_no_validation(block) return coinstate
def read_chain_from_disk() -> CoinState: if os.path.isfile('chain.cache'): print("Reading cached chain") with open('chain.cache', 'rb') as file: coinstate = CoinState.load(lambda: pickle.load(file)) else: coinstate = CoinState.zero() rewrite = False if os.path.isdir('chain'): # the code below is no longer needed by normal users, but some old testcases still rely on it: for filename in sorted(os.listdir('chain')): (height_str, hash_str) = filename.split("-") (height, hash) = (int(height_str), computer(hash_str)) if hash not in coinstate.block_by_hash: if height % 1000 == 0: print(filename) if os.path.getsize(f"chain/{filename}") == 0: print("Stopping at empty block file: %s" % filename) break with open(Path("chain") / filename, 'rb') as f: try: block = Block.stream_deserialize(f) except Exception as e: raise Exception("Corrupted block on disk: %s" % filename) from e try: coinstate = coinstate.add_block_no_validation(block) except Exception: print("Failed to add block at height=%d, previous_hash=%s" % (block.height, human(block.header.summary.previous_block_hash))) break rewrite = True if rewrite: DiskInterface().write_chain_cache_to_disk(coinstate) return coinstate
def test_validate_block_by_itself_invalid_coinbase_transaction(): coinstate = CoinState.empty() transactions = [ Transaction(inputs=[ Input( OutputReference(b'x' * 32, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(1, example_public_key)]) ] summary = construct_minable_summary(coinstate, transactions, 1615209942, 39) evidence = construct_pow_evidence(coinstate, summary, 0, transactions) block = Block(BlockHeader(summary, evidence), transactions) with pytest.raises(ValidateTransactionError, match=".*thin air.*"): validate_block_by_itself(block, 1615209942)
def test_block_serialization(): block = Block( header=BlockHeader( summary=example_block_summary, pow_evidence=example_pow_evidence, ), transactions=[ Transaction( inputs=[ Input(output_reference=OutputReference(b"b" * 32, 1234), signature=SECP256k1Signature(b"b" * 64)) ], outputs=[ Output(value=1582, public_key=SECP256k1PublicKey(b"g" * 64)) ], ) ] * 2, ) serialize_and_deserialize(block)
def broadcast_block(self, block: Block) -> None: self.local_peer.logger.info("%15s ChainManager.broadcast_block(%s)" % ("", human(block.hash()))) self.broadcast_message(DataMessage(DATA_BLOCK, block))
def read_chain_from_disk() -> CoinState: if os.path.isfile('chain.cache'): print("Reading cached chain") with open('chain.cache', 'rb') as file: coinstate = CoinState.load(lambda: pickle.load(file)) else: try: print("Pre-download blockchain from trusted source to 'chain.zip'") with urllib.request.urlopen(TRUSTED_BLOCKCHAIN_ZIP) as resp: with open('chain.zip', 'wb') as outfile: outfile.write(resp.read()) print("Reading initial chain from zipfile") coinstate = CoinState.zero() with zipfile.ZipFile('chain.zip') as zip: for entry in zip.infolist(): if not entry.is_dir(): filename = entry.filename.split('/')[1] height = int(filename.split("-")[0]) if height % 1000 == 0: print(filename) data = zip.read(entry) block = Block.stream_deserialize(BytesIO(data)) coinstate = coinstate.add_block_no_validation(block) except Exception: print( "Error reading zip file. We'll start with an empty blockchain instead." + traceback.format_exc()) coinstate = CoinState.zero() rewrite = False if os.path.isdir('chain'): # the code below is no longer needed by normal users, but some old testcases still rely on it: for filename in sorted(os.listdir('chain')): (height_str, hash_str) = filename.split("-") (height, hash) = (int(height_str), computer(hash_str)) if hash not in coinstate.block_by_hash: if height % 1000 == 0: print(filename) if os.path.getsize(f"chain/{filename}") == 0: print("Stopping at empty block file: %s" % filename) break with open(Path("chain") / filename, 'rb') as f: try: block = Block.stream_deserialize(f) except Exception as e: raise Exception("Corrupted block on disk: %s" % filename) from e try: coinstate = coinstate.add_block_no_validation(block) except Exception: print( "Failed to add block at height=%d, previous_hash=%s" % (block.height, human(block.header.summary.previous_block_hash))) break rewrite = True if rewrite: DiskInterface().write_chain_cache_to_disk(coinstate) return coinstate
def block_filename(block: Block) -> str: return "%08d-%s" % (block.height, human(block.hash()))