So, I understand transactions are only validated syntactically, but I'm struggling to understand why that is the case? To be more specific, why isn't there an exactly once (and current timestamp > prior timestamp) semantic for timestamps? Wouldn't forcing semantics for timestamps enable total ordering?
Timestamps are only validated to be within certain ranges.
Transaction data is only useful to the network, in that it serves to allow Full Nodes or Coordinator(s) the ability to reject transactions that are outside a certain range. The usefulness of this is not clear because timestamps generated by nodes have a wide latitude in the past and up to 2 hours of latitude in the future.
For each IRI software version build, the minimum timestamp is set during the build. For example, in IRI version 184.108.40.206, the time stamp minimum is set to '1517180400' seconds UNIX time or 'Sun Jan 28 23:00:00 2018 UTC' in regular time. See TransactionValidator.java v 220.127.116.11
The maximum timestamp is 2 hours into the future from the current time on the machine that is being used to do the checking.
Transaction vs. Attachment Timestamps
IOTA transactions carry their timestamp data encoded as seconds. However, transaction attachments carry their timestamp data encoded as milliseconds.
The Transaction timestamps are checked in the following areas of operation:
- API call to 'attachToTangle'
- API call to 'broadcastTransactions'
- API call to 'storeTransactions'
When the Coordinator(s) broadcast a Milestone, it also verifies that the transactions carry valid timestamps according to the clock set on the machine used.
When a timestamp is rejected in the API, the software will report "Invalid transaction timestamp" internally. It will log this and then return the caller with the details of the exception.
These actions ensure, that if followed, a machine called to perform these functions will reject transactions with timestamps that are out of the ranges allowed when their API is called. This will also ensure that nodes that verify transactions with other nodes can find out if they are rejected - perhaps by Coordinator nodes or other trusted nodes within the network.
The timestamp checking in Coordinator Milestone broadcasts also ensures that only transactions with valid timestamps - according to the Coordinators - are broadcast and included as tips to confirmed transactions on the network.
If the clock on Coordinator machines is not in sync with the actual time server clocks on the internet, then the transactions it broadcasts may have invalid timestamps. This could lead to rejection of all new transactions on the network.
Furthermore, if machines are not following the official IRI reference model, then nodes may accept to store and broadcast -and even generate- transactions with timestamps that are invalid or within a range that they might be accepted on some machines but rejected on others.
For example, a node could publish a transaction that is accepted by a handful of machines (Coordinators or full nodes) because machine clocks are off by small amounts of seconds or even milliseconds.
If an API call that has more than one transaction in the payload carries a single invalid timestamp, the entire list of transactions is rejected.
If a node is honest, it may still accept an invalid timestamp because it is within range, even though the timestamp is false.
If a node has cached transactions, or a server has cached or stores transactions, in the even of a disruption they will all be rejected by the network.
The problem here is, we can't prove, if the timestamp is correct or not.
Setting the timestamp back to 01.01.1900:
Case 1: The node is honest and rejects the transaction, because the timestamp is not correctly dated -> everything is good
Case 2: The node is NOT honest and distributes the transaction further. Now other nodes have no way of knowing, if the timestamp was legit or not.