Now this one time ticket needs to generated before entering the metro station and the qr code is scanned at * both entry and exit*.
I think the entire system works on daily rotating ticket id validated using unique hashes where a ticket validity period is tracked. I think this should be enough to ensure non-reuse of same ticket.
The caveat is, I have always only bough one time ticket which is the only mode allowed in qr. For daily traveller's, they need to buy token/card which is NFC based.
We actually have this for suburban trains, it's just a receipt with a 1D barcode on it. You use the barcode to open the turnstile (on some stations where they are installed), but otherwise the tickets are checked by controllers that occasionally go through trains.
For getting around a city though, I don't see much of a good use case. In my city, if you're here for at least several days, you're expected to buy the refillable card. If you're only here briefly and only need to use the metro a couple times, it's 1.5x more expensive but you'd buy tokens or tap with your bank card.
The ticket itself just has to encode an ID, and then the central database contains an entry for that ID that is checked by the gate in real time. When the ticket is scanned at a gate, the database gets updated.
And what about all those transfer discounts some cities have? Like if you're taking the subway and a bus within some timeframe, you still only pay once.
The thing with plane and long-distance train tickets is that you buy them for a specific route. So all the checking only needs to be done at your departure station/airport, the code for which is encoded in the ticket, and the rest of the system doesn't need to know anything about it. But you can't do that with city transport. When there aren't multi-use tickets, people would often buy multiple single-use ones at a time and use them as the need arises, without knowing in advance when, where, and from where they'll be going.