async def test_invalid_coinbase_height(self, initial_blockchain): blocks, b = initial_blockchain # Coinbase height invalid block_bad = FullBlock( blocks[9].header_block, Body( CoinbaseInfo( uint32(3), blocks[9].body.coinbase.amount, blocks[9].body.coinbase.puzzle_hash, ), blocks[9].body.coinbase_signature, blocks[9].body.fees_target_info, blocks[9].body.aggregated_signature, blocks[9].body.solutions_generator, blocks[9].body.cost, ), ) assert (await b.receive_block(block_bad)) == ReceiveBlockResult.INVALID_BLOCK
async def request_header_hash( self, request: farmer_protocol.RequestHeaderHash ) -> OutboundMessageGenerator: """ Creates a block body and header, with the proof of space, coinbase, and fee targets provided by the farmer, and sends the hash of the header data back to the farmer. """ plot_seed: bytes32 = request.proof_of_space.get_plot_seed() # Checks that the proof of space is valid quality_string: bytes = Verifier().validate_proof( plot_seed, request.proof_of_space.size, request.challenge_hash, bytes(request.proof_of_space.proof), ) assert quality_string async with self.store.lock: # Retrieves the correct head for the challenge heads: List[HeaderBlock] = self.blockchain.get_current_tips() target_head: Optional[HeaderBlock] = None for head in heads: assert head.challenge if head.challenge.get_hash() == request.challenge_hash: target_head = head if target_head is None: # TODO: should we still allow the farmer to farm? log.warning( f"Challenge hash: {request.challenge_hash} not in one of three heads" ) return # TODO: use mempool to grab best transactions, for the selected head transactions_generator: bytes32 = sha256(b"").digest() # TODO: calculate the fees of these transactions fees: FeesTarget = FeesTarget(request.fees_target_puzzle_hash, uint64(0)) aggregate_sig: Signature = PrivateKey.from_seed(b"12345").sign( b"anything") # TODO: calculate aggregate signature based on transactions # TODO: calculate cost of all transactions cost = uint64(0) # Creates a block with transactions, coinbase, and fees body: Body = Body( request.coinbase, request.coinbase_signature, fees, aggregate_sig, transactions_generator, cost, ) # Creates the block header prev_header_hash: bytes32 = target_head.header.get_hash() timestamp: uint64 = uint64(int(time.time())) # TODO: use a real BIP158 filter based on transactions filter_hash: bytes32 = token_bytes(32) proof_of_space_hash: bytes32 = request.proof_of_space.get_hash() body_hash: Body = body.get_hash() extension_data: bytes32 = bytes32([0] * 32) block_header_data: HeaderData = HeaderData( prev_header_hash, timestamp, filter_hash, proof_of_space_hash, body_hash, extension_data, ) block_header_data_hash: bytes32 = block_header_data.get_hash() # self.stores this block so we can submit it to the blockchain after it's signed by harvester await self.store.add_candidate_block(proof_of_space_hash, body, block_header_data, request.proof_of_space) message = farmer_protocol.HeaderHash(proof_of_space_hash, block_header_data_hash) yield OutboundMessage(NodeType.FARMER, Message("header_hash", message), Delivery.RESPOND)
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