def create_next_block( self, input_constants: Dict, prev_block: FullBlock, timestamp: uint64, update_difficulty: bool, difficulty: uint64, min_iters: uint64, seed: bytes = b"", reward_puzzlehash: bytes32 = None, transactions: Program = None, aggsig: BLSSignature = None, fees: uint64 = uint64(0), ) -> FullBlock: """ Creates the next block with the specified details. """ test_constants: Dict[str, Any] = constants.copy() for key, value in input_constants.items(): test_constants[key] = value assert prev_block.proof_of_time is not None if update_difficulty: challenge = Challenge( prev_block.proof_of_space.challenge_hash, std_hash( prev_block.proof_of_space.get_hash() + prev_block.proof_of_time.output.get_hash() ), difficulty, ) else: challenge = Challenge( prev_block.proof_of_space.challenge_hash, std_hash( prev_block.proof_of_space.get_hash() + prev_block.proof_of_time.output.get_hash() ), None, ) return self._create_block( test_constants, challenge.get_hash(), uint32(prev_block.height + 1), prev_block.header_hash, prev_block.header.data.total_iters, prev_block.weight, timestamp, uint64(difficulty), min_iters, seed, False, reward_puzzlehash, transactions, aggsig, fees, )
def create_next_block( self, test_constants: ConsensusConstants, prev_block: FullBlock, timestamp: uint64, update_difficulty: bool, difficulty: int, min_iters: int, seed: bytes = b"", reward_puzzlehash: bytes32 = None, transactions: Program = None, aggsig: G2Element = None, fees: uint64 = uint64(0), ) -> FullBlock: """ Creates the next block with the specified details. """ assert prev_block.proof_of_time is not None if update_difficulty: challenge = Challenge( prev_block.proof_of_space.challenge_hash, std_hash(prev_block.proof_of_space.get_hash() + prev_block.proof_of_time.output.get_hash()), uint64(difficulty), ) else: challenge = Challenge( prev_block.proof_of_space.challenge_hash, std_hash(prev_block.proof_of_space.get_hash() + prev_block.proof_of_time.output.get_hash()), None, ) return self._create_block( test_constants, challenge.get_hash(), uint32(prev_block.height + 1), prev_block.header_hash, prev_block.header.data.total_iters, prev_block.weight, timestamp, uint64(difficulty), min_iters, seed, False, reward_puzzlehash, transactions, aggsig, fees, )
async def proof_of_time_finished( self, request: timelord_protocol.ProofOfTimeFinished ) -> OutboundMessageGenerator: """ A proof of time, received by a peer timelord. We can use this to complete a block, and call the block routine (which handles propagation and verification of blocks). """ async with self.store.lock: dict_key = ( request.proof.challenge_hash, request.proof.number_of_iterations, ) unfinished_block_obj: Optional[ FullBlock] = await self.store.get_unfinished_block(dict_key) if not unfinished_block_obj: log.warning( f"Received a proof of time that we cannot use to complete a block {dict_key}" ) return prev_full_block = await self.store.get_block( unfinished_block_obj.prev_header_hash) assert prev_full_block prev_block: HeaderBlock = prev_full_block.header_block difficulty: uint64 = self.blockchain.get_next_difficulty( unfinished_block_obj.prev_header_hash) assert prev_block.challenge challenge: Challenge = Challenge( request.proof.challenge_hash, unfinished_block_obj.header_block.proof_of_space.get_hash(), request.proof.output.get_hash(), uint32(prev_block.challenge.height + 1), uint64(prev_block.challenge.total_weight + difficulty), uint64(prev_block.challenge.total_iters + request.proof.number_of_iterations), ) new_header_block = HeaderBlock( unfinished_block_obj.header_block.proof_of_space, request.proof, challenge, unfinished_block_obj.header_block.header, ) new_full_block: FullBlock = FullBlock(new_header_block, unfinished_block_obj.body) async with self.store.lock: sync_mode = await self.store.get_sync_mode() if sync_mode: async with self.store.lock: await self.store.add_potential_future_block(new_full_block) else: async for msg in self.block(peer_protocol.Block(new_full_block)): yield msg
def get_challenge(self, block: FullBlock) -> Optional[Challenge]: if block.proof_of_time is None: return None if block.prev_header_hash not in self.headers and block.height > 0: return None prev_challenge_hash = block.proof_of_space.challenge_hash new_difficulty: Optional[uint64] if (block.height + 1) % self.constants[ "DIFFICULTY_EPOCH"] == self.constants["DIFFICULTY_DELAY"]: new_difficulty = get_next_difficulty(self.constants, self.headers, self.height_to_hash, block.header) else: new_difficulty = None return Challenge( prev_challenge_hash, std_hash(block.proof_of_space.get_hash() + block.proof_of_time.output.get_hash()), new_difficulty, )
def _create_block( self, test_constants: Dict, challenge_hash: bytes32, height: uint32, prev_header_hash: bytes32, prev_iters: uint64, prev_weight: uint64, timestamp: uint64, difficulty: uint64, ips: uint64, seed: bytes, ) -> FullBlock: """ Creates a block with the specified details. Uses the stored plots to create a proof of space, and also evaluates the VDF for the proof of time. """ prover = None plot_pk = None plot_sk = None qualities: List[bytes] = [] for pn in range(num_plots): # Allow passing in seed, to create reorgs and different chains seeded_pn = (pn + 17 * int.from_bytes(seed, "big")) % num_plots filename = self.filenames[seeded_pn] plot_pk = plot_pks[seeded_pn] plot_sk = plot_sks[seeded_pn] prover = DiskProver(os.path.join(self.plot_dir, filename)) qualities = prover.get_qualities_for_challenge(challenge_hash) if len(qualities) > 0: break assert prover assert plot_pk assert plot_sk if len(qualities) == 0: raise NoProofsOfSpaceFound("No proofs for this challenge") proof_xs: bytes = prover.get_full_proof(challenge_hash, 0) proof_of_space: ProofOfSpace = ProofOfSpace( challenge_hash, pool_pk, plot_pk, k, [uint8(b) for b in proof_xs]) number_iters: uint64 = pot_iterations.calculate_iterations( proof_of_space, difficulty, ips, test_constants["MIN_BLOCK_TIME"]) disc: int = create_discriminant( challenge_hash, test_constants["DISCRIMINANT_SIZE_BITS"]) start_x: ClassGroup = ClassGroup.from_ab_discriminant(2, 1, disc) y_cl, proof_bytes = create_proof_of_time_nwesolowski( disc, start_x, number_iters, disc, n_wesolowski) output = ClassgroupElement(y_cl[0], y_cl[1]) proof_of_time = ProofOfTime( challenge_hash, number_iters, output, n_wesolowski, [uint8(b) for b in proof_bytes], ) coinbase: CoinbaseInfo = CoinbaseInfo( height, block_rewards.calculate_block_reward(uint32(height)), coinbase_target, ) coinbase_sig: PrependSignature = pool_sk.sign_prepend(bytes(coinbase)) fees_target: FeesTarget = FeesTarget(fee_target, uint64(0)) solutions_generator: bytes32 = sha256(seed).digest() cost = uint64(0) body: Body = Body(coinbase, coinbase_sig, fees_target, None, solutions_generator, cost) header_data: HeaderData = HeaderData( prev_header_hash, timestamp, bytes([0] * 32), proof_of_space.get_hash(), body.get_hash(), bytes([0] * 32), ) header_hash_sig: PrependSignature = plot_sk.sign_prepend( header_data.get_hash()) header: Header = Header(header_data, header_hash_sig) challenge = Challenge( challenge_hash, proof_of_space.get_hash(), proof_of_time.get_hash(), height, uint64(prev_weight + difficulty), uint64(prev_iters + number_iters), ) header_block = HeaderBlock(proof_of_space, proof_of_time, challenge, header) full_block: FullBlock = FullBlock(header_block, body) return full_block
async def create( key_config: Dict, config: Dict, db_path: Path, constants: Dict, name: str = None, ): self = WalletStateManager() self.config = config self.constants = constants if name: self.log = logging.getLogger(name) else: self.log = logging.getLogger(__name__) self.lock = asyncio.Lock() self.db_connection = await aiosqlite.connect(db_path) self.wallet_store = await WalletStore.create(self.db_connection) self.tx_store = await WalletTransactionStore.create(self.db_connection) self.puzzle_store = await WalletPuzzleStore.create(self.db_connection) self.user_store = await WalletUserStore.create(self.db_connection) self.lca = None self.sync_mode = False self.height_to_hash = {} self.block_records = await self.wallet_store.get_lca_path() genesis = FullBlock.from_bytes(self.constants["GENESIS_BLOCK"]) self.genesis = genesis self.state_changed_callback = None self.pending_tx_callback = None self.difficulty_resets_prev = {} self.db_path = db_path main_wallet_info = await self.user_store.get_wallet_by_id(1) assert main_wallet_info is not None self.main_wallet = await Wallet.create(config, key_config, self, main_wallet_info) self.wallets = {} main_wallet = await Wallet.create(config, key_config, self, main_wallet_info) self.wallets[main_wallet_info.id] = main_wallet for wallet_info in await self.get_all_wallets(): self.log.info(f"wallet_info {wallet_info}") if wallet_info.type == WalletType.STANDARD_WALLET: if wallet_info.id == 1: continue wallet = await Wallet.create(config, key_config, self, main_wallet_info) self.wallets[wallet_info.id] = wallet elif wallet_info.type == WalletType.RATE_LIMITED: wallet = await RLWallet.create( config, key_config, self, wallet_info, self.main_wallet, ) self.wallets[wallet_info.id] = wallet async with self.puzzle_store.lock: await self.create_more_puzzle_hashes(from_zero=True) if len(self.block_records) > 0: # Initializes the state based on the DB block records # Header hash with the highest weight self.lca = max((item[1].weight, item[0]) for item in self.block_records.items())[1] for key, value in self.block_records.items(): self.height_to_hash[value.height] = value.header_hash # Checks genesis block is the same in config, as in DB assert self.block_records[genesis.header_hash].height == 0 assert self.block_records[ genesis.header_hash].weight == genesis.weight else: # Loads the genesis block if there are no blocks genesis_challenge = Challenge( genesis.proof_of_space.challenge_hash, std_hash(genesis.proof_of_space.get_hash() + genesis.proof_of_time.output.get_hash()), None, ) genesis_hb = HeaderBlock( genesis.proof_of_space, genesis.proof_of_time, genesis_challenge, genesis.header, ) await self.receive_block( BlockRecord( genesis.header_hash, genesis.prev_header_hash, uint32(0), genesis.weight, [], [], genesis_hb.header.data.total_iters, genesis_challenge.get_hash(), ), genesis_hb, ) return self