1+ import Atomics
12import Foundation
23import HederaProtobufs
34
@@ -15,6 +16,11 @@ public struct TransactionId: Sendable, Equatable, Hashable, ExpressibleByStringL
1516 public let scheduled : Bool
1617 public let nonce : Int32 ?
1718
19+ private static let nanosPerMillisecond : UInt64 = 1_000_000
20+ private static let nanosToRemove : UInt64 = 10_000_000_000
21+ private static let timestampIncrement : UInt64 = 1_000
22+ private static let monotonicTime = ManagedAtomic < UInt64 > ( 0 )
23+
1824 internal init ( accountId: AccountId , validStart: Timestamp , scheduled: Bool = false , nonce: Int32 ? = nil ) {
1925 self . accountId = accountId
2026 self . validStart = validStart
@@ -24,11 +30,28 @@ public struct TransactionId: Sendable, Equatable, Hashable, ExpressibleByStringL
2430
2531 /// Generates a new transaction ID for the given account ID.
2632 public static func generateFrom( _ accountId: AccountId ) -> Self {
27- let random = UInt64 . random ( in: 5_000_000_000 ..< 8_000_000_000 )
28-
29- let validStart = Timestamp . now. subtracting ( nanos: random)
30-
31- return Self ( accountId: accountId, validStart: validStart)
33+ var currentTime : UInt64
34+ var lastTime : UInt64
35+
36+ repeat {
37+ // Get the current time in nanoseconds and remove 10 seconds for time drift allowance.
38+ // This ensures transaction is within the allowed time window.
39+ currentTime = UInt64 ( Date ( ) . timeIntervalSince1970 * 1_000_000_000 ) - nanosToRemove
40+
41+ // Retrieve the last recorded time
42+ lastTime = monotonicTime. load ( ordering: . relaxed)
43+
44+ // Ensure strictly increasing timestamps
45+ if currentTime <= lastTime {
46+ currentTime = lastTime + timestampIncrement
47+ }
48+ } while !monotonicTime. compareExchange (
49+ expected: lastTime,
50+ desired: currentTime,
51+ ordering: . relaxed
52+ ) . exchanged
53+
54+ return Self ( accountId: accountId, validStart: Timestamp ( fromUnixTimestampNanos: currentTime) )
3255 }
3356
3457 /// Generates a new transaction ID for chunks.
0 commit comments