docs: def snapshot(self, block_id, oplist):
          """
          Given the currnet block ID and the set of operations committed,
          find the consensus hash that represents the state of the virtual chain.
          
          The consensus hash is calculated as a Merkle skip-list.  It incorporates:
          * block K's operations 
          * block K - 1's consensus hash 
          * block K - 2 - 1's consensus hash 
          * block K - 4 - 2 - 1's consensus hash, 
          ...
          * block K - (2**i - 1)'s consensus hash
          
          The purpose of this construction is that it reduces the number of queries 
          a client needs to verify the integrity of previously-processed operations
          to a *sublinear* function of the length of the virtual blockchain.
          
          For example, if there are 15 blocks in the virtual chain, and a client has 
          the consensus hash for block 15 (ch[15]) but wants to verify an operation at block 3, the 
          client would:
          1.    Fetch ops[15], ch[14], ch[12], ch[8], ch[0]
          2.    Verify (1) with ch[15], so ch[8] is trusted.
          3.    Fetch ops[8], ch[7], ch[5], ch[1]
          4.    Verify (3) with ch[8], so ch[5] is trusted
          5.    Fetch ops[5], ch[3]
          6.    Verify (5) and ch[1] from (3) with ch[5], so ch[3] is trusted
          7.    Fetch ops[3], ch[2]
          8.    Verify (7) and ch[0] from (1) with ch[3], so ops[3] is trusted
          9.    Verify op in ops[3]
  
          Returns (consensus hash, ops_hash)
          """
          
          assert self.setup, "Not set up yet.  Call .db_setup() first!"
          log.debug("Snapshotting block {}".format(block_id))
          
          serialized_ops = []
          for opdata in oplist:
              serialized_record = StateEngine.serialize_op(opdata['virtualchain_opcode'], opdata, self.opfields)
              serialized_ops.append( serialized_record )
  
          previous_consensus_hashes = []
          k = block_id
          i = 1
          while k - (2**i - 1) >= self.impl.get_first_block_id():
              prev_block = k - (2**i - 1)
              prev_ch = self.get_consensus_at(prev_block)
              log.debug("Snapshotting block %s: consensus hash of %s is %s" % (block_id, prev_block, prev_ch))
  
              if prev_ch is None:
                  log.error("BUG: None consensus for %s" % prev_block )
                  traceback.print_stack()
                  os.abort()
  
              previous_consensus_hashes.append(prev_ch)
              i += 1
  
          consensus_hash, ops_hash = StateEngine.make_snapshot(serialized_ops, previous_consensus_hashes) 
          return consensus_hash, ops_hash