code: def locked_blocks_iterator(blockfile, start_info=(0, 0), cached_headers=50, batch_size=50):
      
      f = blockfile
      current_state = []
  
      def change_state(bc, ops):
          for op, bh, work in ops:
              if op == 'add':
                  current_state.append(bh)
                  pass
              else:
                  current_state.pop()
      bc = BlockChain()
      bc.add_change_callback(change_state)
      bhs = []
      index = 0
      info_offset = start_info
      while 1:
          v = blockfile.next_offset(info_offset)
          if v is None:
              break
          block_offset, info_offset = v
          f.jump_to(block_offset)
          bh = Block.parse_as_header(f)
          bh.info = block_offset
  
          bhs.append(bh)
          if len(bhs) > batch_size:
              bc.add_headers(bhs)
              bhs = []
              if len(current_state) > cached_headers:
                  for bh in current_state[:cached_headers]:
                      bh.index = index
                      yield bh
                      index += 1
                      bc.lock_to_index(index)
                  current_state = current_state[cached_headers:]
docs: This method loads blocks from disk, skipping any orphan blocks.