Skip to content

Commit

Permalink
Handle overflow for TransactionId timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
RickyLB authored Feb 7, 2025
1 parent b8cf5ad commit fb101ea
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 8 deletions.
1 change: 0 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
[submodule "protobufs"]
path = protobufs
url = https://github.com/hashgraph/hedera-services.git
sparseCheckout = true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ task submodule:install
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

# generate GRPC (if needed)
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
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
```

### Integration Tests
Expand Down
33 changes: 28 additions & 5 deletions Sources/Hedera/TransactionId.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Atomics
import Foundation
import HederaProtobufs

Expand All @@ -15,6 +16,11 @@ public struct TransactionId: Sendable, Equatable, Hashable, ExpressibleByStringL
public let scheduled: Bool
public let nonce: Int32?

private static let nanosPerMillisecond: UInt64 = 1_000_000
private static let nanosToRemove: UInt64 = 10_000_000_000
private static let timestampIncrement: UInt64 = 1_000
private static let monotonicTime = ManagedAtomic<UInt64>(0)

internal init(accountId: AccountId, validStart: Timestamp, scheduled: Bool = false, nonce: Int32? = nil) {
self.accountId = accountId
self.validStart = validStart
Expand All @@ -24,11 +30,28 @@ public struct TransactionId: Sendable, Equatable, Hashable, ExpressibleByStringL

/// Generates a new transaction ID for the given account ID.
public static func generateFrom(_ accountId: AccountId) -> Self {
let random = UInt64.random(in: 5_000_000_000..<8_000_000_000)

let validStart = Timestamp.now.subtracting(nanos: random)

return Self(accountId: accountId, validStart: validStart)
var currentTime: UInt64
var lastTime: UInt64

repeat {
// Get the current time in nanoseconds and remove 10 seconds for time drift allowance.
// This ensures transaction is within the allowed time window.
currentTime = UInt64(Date().timeIntervalSince1970 * 1_000_000_000) - nanosToRemove

// Retrieve the last recorded time
lastTime = monotonicTime.load(ordering: .relaxed)

// Ensure strictly increasing timestamps
if currentTime <= lastTime {
currentTime = lastTime + timestampIncrement
}
} while !monotonicTime.compareExchange(
expected: lastTime,
desired: currentTime,
ordering: .relaxed
).exchanged

return Self(accountId: accountId, validStart: Timestamp(fromUnixTimestampNanos: currentTime))
}

/// Generates a new transaction ID for chunks.
Expand Down
2 changes: 1 addition & 1 deletion protobufs

0 comments on commit fb101ea

Please sign in to comment.