Skip to content

Commit fb101ea

Browse files
authored
Handle overflow for TransactionId timestamp
1 parent b8cf5ad commit fb101ea

File tree

4 files changed

+30
-8
lines changed

4 files changed

+30
-8
lines changed

.gitmodules

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
[submodule "protobufs"]
22
path = protobufs
33
url = https://github.com/hashgraph/hedera-services.git
4-
sparseCheckout = true

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ task submodule:install
9393
protoc --swift_opt=Visibility=Public --swift_opt=FileNaming=PathToUnderscores --swift_out=./Sources/HederaProtobufs/Services --proto_path=./Sources/HederaProtobufs/Protos/services Sources/HederaProtobufs/Protos/services/*.proto
9494

9595
# generate GRPC (if needed)
96-
protoc --grpc-swift_opt=Visibility=Public,Server=false --grpc-swift_out=./Sources/HederaProtobufs/Services --proto_path=./Sources/HederaProtobufs/Protos/services Sources/HederaProtobufs/HederaProtobufs/Protos/services/*.proto
96+
protoc --grpc-swift_opt=Visibility=Public,Server=false --grpc-swift_out=./Sources/HederaProtobufs/Services --proto_path=./Sources/HederaProtobufs/Protos/services Sources/HederaProtobufs/Protos/services/*.proto
9797
```
9898

9999
### Integration Tests

Sources/Hedera/TransactionId.swift

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Atomics
12
import Foundation
23
import 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.

protobufs

0 commit comments

Comments
 (0)