From 1e86e556772cc47aad25360bc8e5ad94b6ecc090 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Thu, 19 Dec 2024 21:10:22 +1300 Subject: [PATCH] Bump testvectors (#253) * codec tests passing * pass safrole * fix * assurances tests --- .swiftlint.yml | 2 +- .../Config/ProtocolConfig+Preset.swift | 40 ++++++++ .../RuntimeProtocols/Assurances.swift | 87 ++++++++++++++++++ .../Blockchain/RuntimeProtocols/Runtime.swift | 38 ++------ .../Blockchain/RuntimeProtocols/Safrole.swift | 1 + .../Sources/Blockchain/State/State.swift | 2 + .../Blockchain/Types/EpochMarker.swift | 3 + .../Types/ExtrinsicAvailability.swift | 2 +- .../Sources/Blockchain/Types/WorkItem.swift | 34 +++++-- JAMTests/Tests/JAMTests/AssurancesTests.swift | 91 +++++++++++++++++++ JAMTests/Tests/JAMTests/CodecTests.swift | 26 +++--- .../Tests/JAMTests/RecentHistoryTests.swift | 4 +- JAMTests/Tests/JAMTests/SafroleTests.swift | 27 +----- JAMTests/jamtestvectors | 2 +- Utils/Sources/Utils/ConfigSizeBitString.swift | 6 +- .../xcshareddata/swiftpm/Package.resolved | 6 +- 16 files changed, 289 insertions(+), 82 deletions(-) create mode 100644 Blockchain/Sources/Blockchain/RuntimeProtocols/Assurances.swift create mode 100644 JAMTests/Tests/JAMTests/AssurancesTests.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 07c102d5..a03321e8 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -25,7 +25,7 @@ line_length: ignores_function_declarations: true function_body_length: - warning: 200 + warning: 300 error: 500 redundant_void_return: diff --git a/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift b/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift index cc64c7f4..5168f32f 100644 --- a/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift +++ b/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift @@ -83,6 +83,46 @@ extension Ref where T == ProtocolConfig { pvmMemoryPageSize: 1 << 12 )) + public static let tiny = Ref(ProtocolConfig( + auditTranchePeriod: 8, + additionalMinBalancePerStateItem: 10, + additionalMinBalancePerStateByte: 1, + serviceMinBalance: 100, + totalNumberOfCores: 2, + preimagePurgePeriod: 28800, + epochLength: 12, + auditBiasFactor: 2, + coreAccumulationGas: Gas(100_000), + workPackageAuthorizerGas: Gas(1_000_000), + workPackageRefineGas: Gas(500_000_000), + totalAccumulationGas: Gas(341_000_000), + recentHistorySize: 8, + maxWorkItems: 4, + maxDepsInWorkReport: 8, + maxTicketsPerExtrinsic: 3, + maxLookupAnchorAge: 14400, + transferMemoSize: 128, + ticketEntriesPerValidator: 3, + maxAuthorizationsPoolItems: 8, + slotPeriodSeconds: 6, + maxAuthorizationsQueueItems: 80, + coreAssignmentRotationPeriod: 10, + maxServiceCodeSize: 4_000_000, + preimageReplacementPeriod: 5, + totalNumberOfValidators: 6, + erasureCodedPieceSize: 684, + maxWorkPackageManifestEntries: 1 << 11, + maxEncodedWorkPackageSize: 12 * 1 << 20, + segmentSize: 4104, + maxWorkReportOutputSize: 96 * 1 << 10, + erasureCodedSegmentSize: 6, + ticketSubmissionEndSlot: 10, + pvmDynamicAddressAlignmentFactor: 2, + pvmProgramInitInputDataSize: 1 << 24, + pvmProgramInitZoneSize: 1 << 16, + pvmMemoryPageSize: 1 << 12 + )) + public static let mainnet = Ref(ProtocolConfig( auditTranchePeriod: 8, additionalMinBalancePerStateItem: 10, diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/Assurances.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/Assurances.swift new file mode 100644 index 00000000..7d701060 --- /dev/null +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/Assurances.swift @@ -0,0 +1,87 @@ +import Utils + +public enum AssurancesError: Error { + case invalidAssuranceSignature + case assuranceForEmptyCore + case invalidAssuranceParentHash +} + +public protocol Assurances { + var reports: + ConfigFixedSizeArray< + ReportItem?, + ProtocolConfig.TotalNumberOfCores + > + { get } + + var currentValidators: + ConfigFixedSizeArray< + ValidatorKey, + ProtocolConfig.TotalNumberOfValidators + > + { get } +} + +extension Assurances { + public func update( + config: ProtocolConfigRef, + timeslot: TimeslotIndex, + extrinsic: ExtrinsicAvailability, + parentHash: Data32 + ) throws -> ( + newReports: ConfigFixedSizeArray< + ReportItem?, + ProtocolConfig.TotalNumberOfCores + >, + availableReports: [WorkReport] + ) { + var newReports = reports + + for i in 0 ..< newReports.count { + if let report = newReports[i] { + if (report.timeslot + UInt32(config.value.preimageReplacementPeriod)) <= timeslot { + newReports[i] = nil + } + } + } + + for assurance in extrinsic.assurances { + guard assurance.parentHash == parentHash else { + throw AssurancesError.invalidAssuranceParentHash + } + + let hash = Blake2b256.hash(assurance.parentHash, assurance.assurance) + let payload = SigningContext.available + hash.data + let validatorKey = try currentValidators.at(Int(assurance.validatorIndex)) + let pubkey = try Ed25519.PublicKey(from: validatorKey.ed25519) + guard pubkey.verify(signature: assurance.signature, message: payload) else { + throw AssurancesError.invalidAssuranceSignature + } + } + + var availabilityCount = Array(repeating: 0, count: config.value.totalNumberOfCores) + for assurance in extrinsic.assurances { + for (coreIdx, bit) in assurance.assurance.enumerated() where bit { + // ExtrinsicAvailability.validate() ensures that validatorIndex is in range + availabilityCount[coreIdx] += 1 + } + } + + var availableReports = [WorkReport]() + + for (idx, count) in availabilityCount.enumerated() where count > 0 { + guard let report = reports[idx] else { + throw AssurancesError.assuranceForEmptyCore + } + if count >= ProtocolConfig.TwoThirdValidatorsPlusOne.read(config: config) { + availableReports.append(report.workReport) + newReports[idx] = nil // remove available report from pending reports + } + } + + return ( + newReports: newReports, + availableReports: availableReports + ) + } +} diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift index 65dc51bb..bb9a7889 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift @@ -343,36 +343,16 @@ public final class Runtime { // returns available reports public func updateReports(block: BlockRef, state newState: inout State) throws -> [WorkReport] { - for assurance in block.extrinsic.availability.assurances { - let hash = Blake2b256.hash(assurance.parentHash, assurance.assurance) - let payload = SigningContext.available + hash.data - let validatorKey = try newState.currentValidators.at(Int(assurance.validatorIndex)) - let pubkey = try Ed25519.PublicKey(from: validatorKey.ed25519) - guard pubkey.verify(signature: assurance.signature, message: payload) else { - throw Error.invalidAssuranceSignature - } - } - - var availabilityCount = Array(repeating: 0, count: config.value.totalNumberOfCores) - for assurance in block.extrinsic.availability.assurances { - for bit in assurance.assurance where bit { - // ExtrinsicAvailability.validate() ensures that validatorIndex is in range - availabilityCount[Int(assurance.validatorIndex)] += 1 - } - } - - var availableReports = [WorkReport]() - - for (idx, count) in availabilityCount.enumerated() where count > 0 { - guard let report = newState.reports[idx] else { - throw Error.assuranceForEmptyCore - } - if count >= ProtocolConfig.TwoThirdValidatorsPlusOne.read(config: config) { - availableReports.append(report.workReport) - newState.reports[idx] = nil // remove available report from pending reports - } - } + let ( + newReports: newReports, availableReports: availableReports + ) = try newState.update( + config: config, + timeslot: block.header.timeslot, + extrinsic: block.extrinsic.availability, + parentHash: block.header.parentHash + ) + newState.reports = newReports newState.reports = try newState.update(config: config, extrinsic: block.extrinsic.reports) return availableReports diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/Safrole.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/Safrole.swift index 76deae39..bd8f412a 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/Safrole.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/Safrole.swift @@ -302,6 +302,7 @@ extension Safrole { let epochMark = try isEpochChange ? EpochMarker( entropy: newEntropyPool.1, + ticketsEntropy: newEntropyPool.2, validators: ConfigFixedSizeArray(config: config, array: newNextValidators.map(\.bandersnatch)) ) : nil diff --git a/Blockchain/Sources/Blockchain/State/State.swift b/Blockchain/Sources/Blockchain/State/State.swift index d3d69ccc..531169d8 100644 --- a/Blockchain/Sources/Blockchain/State/State.swift +++ b/Blockchain/Sources/Blockchain/State/State.swift @@ -444,6 +444,8 @@ extension State: Safrole { } } +extension State: Assurances {} + extension State: Disputes { public mutating func mergeWith(postState: DisputePostState) { judgements = postState.judgements diff --git a/Blockchain/Sources/Blockchain/Types/EpochMarker.swift b/Blockchain/Sources/Blockchain/Types/EpochMarker.swift index 4506678e..f7c5a700 100644 --- a/Blockchain/Sources/Blockchain/Types/EpochMarker.swift +++ b/Blockchain/Sources/Blockchain/Types/EpochMarker.swift @@ -2,6 +2,7 @@ import Utils public struct EpochMarker: Sendable, Equatable, Codable { public var entropy: Data32 + public var ticketsEntropy: Data32 public var validators: ConfigFixedSizeArray< BandersnatchPublicKey, ProtocolConfig.TotalNumberOfValidators @@ -9,12 +10,14 @@ public struct EpochMarker: Sendable, Equatable, Codable { public init( entropy: Data32, + ticketsEntropy: Data32, validators: ConfigFixedSizeArray< BandersnatchPublicKey, ProtocolConfig.TotalNumberOfValidators > ) { self.entropy = entropy + self.ticketsEntropy = ticketsEntropy self.validators = validators } } diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift index 2b179853..b7c97b6c 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift @@ -58,7 +58,7 @@ extension ExtrinsicAvailability: Validate { throw .assurancesNotSorted } for assurance in assurances { - guard assurance.validatorIndex < UInt32(config.value.totalNumberOfCores) else { + guard assurance.validatorIndex < UInt32(config.value.totalNumberOfValidators) else { throw .invalidValidatorIndex } } diff --git a/Blockchain/Sources/Blockchain/Types/WorkItem.swift b/Blockchain/Sources/Blockchain/Types/WorkItem.swift index ce45879d..9f2eb3e6 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkItem.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkItem.swift @@ -9,6 +9,11 @@ public struct WorkItem: Sendable, Equatable, Codable { case workPackageHash(Data32) } + enum CodingKeys: String, CodingKey { + case root + case index + } + public var root: DataSegmentRootKind public var index: UInt16 @@ -19,16 +24,27 @@ public struct WorkItem: Sendable, Equatable, Codable { // Encodable public func encode(to encoder: Encoder) throws { - var container = encoder.unkeyedContainer() - var indexValue = index - switch root { - case let .segmentRoot(root): - try container.encode(root) - case let .workPackageHash(hash): - try container.encode(hash) - indexValue |= 1 << 15 + if encoder.isJamCodec { + var container = encoder.unkeyedContainer() + var indexValue = index + switch root { + case let .segmentRoot(root): + try container.encode(root) + case let .workPackageHash(hash): + try container.encode(hash) + indexValue |= 1 << 15 + } + try container.encode(indexValue) + } else { + var container = encoder.container(keyedBy: CodingKeys.self) + switch root { + case let .segmentRoot(root): + try container.encode(root, forKey: .root) + case let .workPackageHash(hash): + try container.encode(hash, forKey: .root) + } + try container.encode(index, forKey: .index) } - try container.encode(indexValue) } // Decodable diff --git a/JAMTests/Tests/JAMTests/AssurancesTests.swift b/JAMTests/Tests/JAMTests/AssurancesTests.swift new file mode 100644 index 00000000..7f8446e0 --- /dev/null +++ b/JAMTests/Tests/JAMTests/AssurancesTests.swift @@ -0,0 +1,91 @@ +import Blockchain +import Codec +import Foundation +import Testing +import Utils + +@testable import JAMTests + +struct AssurancesInput: Codable { + var assurances: ExtrinsicAvailability + var timeslot: TimeslotIndex + var parentHash: Data32 +} + +struct AssuranceState: Equatable, Codable, Assurances { + var reports: ConfigFixedSizeArray + var currentValidators: + ConfigFixedSizeArray +} + +struct AssurancesTestcase: Codable { + var input: AssurancesInput + var preState: AssuranceState + var output: Either<[WorkReport], UInt8> + var postState: AssuranceState +} + +enum AssurancesTestVariants: String, CaseIterable { + case tiny + case full + + var config: ProtocolConfigRef { + switch self { + case .tiny: + ProtocolConfigRef.tiny + case .full: + ProtocolConfigRef.mainnet + } + } +} + +struct AssurancesTests { + static func loadTests(variant: AssurancesTestVariants) throws -> [Testcase] { + try TestLoader.getTestcases(path: "assurances/\(variant)", extension: "bin") + } + + func assurancesTests(_ testcase: Testcase, variant: AssurancesTestVariants) throws { + let config = variant.config + let decoder = JamDecoder(data: testcase.data, config: config) + let testcase = try decoder.decode(AssurancesTestcase.self) + + var state = testcase.preState + let result = Result { + try testcase.input.assurances.validate(config: config) + return try state.update( + config: config, timeslot: testcase.input.timeslot, + extrinsic: testcase.input.assurances, + parentHash: testcase.input.parentHash + ) + } + switch result { + case let .success((newReports, availableReports)): + switch testcase.output { + case let .left(reports): + state.reports = newReports + #expect(state == testcase.postState) + #expect(availableReports == reports) + case .right: + Issue.record("Expected error, got \(result)") + } + case .failure: + switch testcase.output { + case .left: + Issue.record("Expected success, got \(result)") + case .right: + // ignore error code because it is unspecified + break + } + } + } + + @Test(arguments: try AssurancesTests.loadTests(variant: .tiny)) + func tinyTests(_ testcase: Testcase) throws { + try assurancesTests(testcase, variant: .tiny) + } + + @Test(arguments: try AssurancesTests.loadTests(variant: .full)) + func fullTests(_ testcase: Testcase) throws { + try assurancesTests(testcase, variant: .full) + } +} diff --git a/JAMTests/Tests/JAMTests/CodecTests.swift b/JAMTests/Tests/JAMTests/CodecTests.swift index d3a1ecc7..92762ec0 100644 --- a/JAMTests/Tests/JAMTests/CodecTests.swift +++ b/JAMTests/Tests/JAMTests/CodecTests.swift @@ -120,7 +120,7 @@ struct CodecTests { if value is WorkResult { return [ "code_hash": json["codeHash"]!, - "gas": json["gasRatio"]!, + "accumulate_gas": json["gasRatio"]!, "payload_hash": json["payloadHash"]!, "service_id": json["serviceIndex"]!, "result": json["output"]!["success"] == nil ? json["output"]! : [ @@ -133,7 +133,8 @@ struct CodecTests { "service": json["serviceIndex"]!, "code_hash": json["codeHash"]!, "payload": json["payloadBlob"]!, - "gas_limit": json["gasLimit"]!, + "refine_gas_limit": json["refineGasLimit"]!, + "accumulate_gas_limit": json["accumulateGasLimit"]!, "import_segments": json["inputs"]!.array!.map { item in [ "tree_root": item["root"]!, @@ -210,7 +211,7 @@ struct CodecTests { "parent_state_root": json["priorStateRoot"]!, "extrinsic_hash": json["extrinsicsHash"]!, "slot": json["timeslot"]!, - "epoch_mark": json["epoch"] ?? .null, + "epoch_mark": transform(json["epoch"] ?? .null, value: value.epoch as Any), "tickets_mark": transform(json["winningTickets"] ?? .null, value: value.winningTickets as Any), "offenders_mark": transform(json["offendersMarkers"]!, value: value.offendersMarkers), "author_index": json["authorIndex"]!, @@ -218,6 +219,13 @@ struct CodecTests { "seal": json["seal"]!, ].json } + if value is EpochMarker { + return [ + "entropy": json["entropy"]!, + "tickets_entropy": json["ticketsEntropy"]!, + "validators": json["validators"]!, + ].json + } var dict = [String: JSON]() for field in Mirror(reflecting: value).children { @@ -297,18 +305,14 @@ struct CodecTests { @Test func work_item() throws { - withKnownIssue("need bump test vectors") { - let (actual, expected) = try Self.test(WorkItem.self, path: "work_item") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(WorkItem.self, path: "work_item") + #expect(actual == expected) } @Test func work_package() throws { - withKnownIssue("need bump test vectors") { - let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") + #expect(actual == expected) } @Test diff --git a/JAMTests/Tests/JAMTests/RecentHistoryTests.swift b/JAMTests/Tests/JAMTests/RecentHistoryTests.swift index ecfce568..9f17fcbe 100644 --- a/JAMTests/Tests/JAMTests/RecentHistoryTests.swift +++ b/JAMTests/Tests/JAMTests/RecentHistoryTests.swift @@ -18,7 +18,7 @@ struct RecentHistoryInput: Codable { var workPackages: [ReportedWorkPackage] } -struct RecentHisoryTestcase: Codable { +struct RecentHistoryTestcase: Codable { var input: RecentHistoryInput var preState: RecentHistory var postState: RecentHistory @@ -32,7 +32,7 @@ struct RecentHistoryTests { @Test(arguments: try loadTests()) func recentHistory(_ testcase: Testcase) throws { let config = ProtocolConfigRef.mainnet - let testcase = try JamDecoder.decode(RecentHisoryTestcase.self, from: testcase.data, withConfig: config) + let testcase = try JamDecoder.decode(RecentHistoryTestcase.self, from: testcase.data, withConfig: config) var state = testcase.preState state.update( diff --git a/JAMTests/Tests/JAMTests/SafroleTests.swift b/JAMTests/Tests/JAMTests/SafroleTests.swift index bc51a975..d0381933 100644 --- a/JAMTests/Tests/JAMTests/SafroleTests.swift +++ b/JAMTests/Tests/JAMTests/SafroleTests.swift @@ -10,7 +10,6 @@ struct SafroleInput: Codable { var slot: UInt32 var entropy: Data32 var extrinsics: ExtrinsicTickets - var offenders: [Ed25519PublicKey] } struct OutputMarks: Codable { @@ -22,18 +21,6 @@ struct OutputMarks: Codable { } struct SafroleState: Equatable, Safrole, Codable { - enum CodingKeys: String, CodingKey { - case timeslot - case entropyPool - case previousValidators - case currentValidators - case nextValidators - case validatorQueue - case ticketsAccumulator - case ticketsOrKeys - case ticketsVerifier - } - // tau var timeslot: UInt32 // eta @@ -74,6 +61,9 @@ struct SafroleState: Equatable, Safrole, Codable { // gammaZ var ticketsVerifier: BandersnatchRingVRFRoot + // ψo + var offenders: [Ed25519PublicKey] + public mutating func mergeWith(postState: SafrolePostState) { timeslot = postState.timeslot entropyPool = postState.entropyPool @@ -98,17 +88,10 @@ enum SafroleTestVariants: String, CaseIterable { case tiny case full - static let tinyConfig = ProtocolConfigRef.mainnet.mutate { config in - config.totalNumberOfValidators = 6 - config.epochLength = 12 - // 10 = 12 * 500/600, not sure what this should be for tiny, but this passes tests - config.ticketSubmissionEndSlot = 10 - } - var config: ProtocolConfigRef { switch self { case .tiny: - Self.tinyConfig + ProtocolConfigRef.tiny case .full: ProtocolConfigRef.mainnet } @@ -130,7 +113,7 @@ struct SafroleTests { config: config, slot: testcase.input.slot, entropy: testcase.input.entropy, - offenders: Set(testcase.input.offenders), + offenders: Set(testcase.preState.offenders), extrinsics: testcase.input.extrinsics ) } diff --git a/JAMTests/jamtestvectors b/JAMTests/jamtestvectors index 41809243..9444ac5c 160000 --- a/JAMTests/jamtestvectors +++ b/JAMTests/jamtestvectors @@ -1 +1 @@ -Subproject commit 418092431e14b1da52dd8040d12ba246cc351f99 +Subproject commit 9444ac5cdd8a6d58965dc330d31df73459270507 diff --git a/Utils/Sources/Utils/ConfigSizeBitString.swift b/Utils/Sources/Utils/ConfigSizeBitString.swift index 5c286efe..bba2ebd1 100644 --- a/Utils/Sources/Utils/ConfigSizeBitString.swift +++ b/Utils/Sources/Utils/ConfigSizeBitString.swift @@ -35,7 +35,7 @@ public struct ConfigSizeBitString: Equatable, Sendable, Cod private func at(unchecked index: Int) -> Bool { let byteIndex = index / 8 let bitIndex = index % 8 - return (bytes[byteIndex] & (1 << bitIndex)) != 0 + return (bytes[relative: byteIndex] & (1 << bitIndex)) != 0 } /// Formats the bitstring in binary digits. @@ -59,9 +59,9 @@ public struct ConfigSizeBitString: Equatable, Sendable, Cod let byteIndex = index / 8 let bitIndex = index % 8 if value { - bytes[byteIndex] |= (1 << bitIndex) + bytes[bytes.relative(offset: byteIndex)] |= (1 << bitIndex) } else { - bytes[byteIndex] &= ~(1 << bitIndex) + bytes[bytes.relative(offset: byteIndex)] &= ~(1 << bitIndex) } } } diff --git a/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index bd080355..6da8821a 100644 --- a/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "8e21a58b6d7f842c098f4e974e374c6d0247726a1d3017dda720b3de822a747b", + "originHash" : "df8d708ee631530dce6fd56811e5100a965c55290ef02b21f0ffdb94c192448c", "pins" : [ { "identity" : "async-channels", @@ -247,7 +247,7 @@ { "identity" : "swift-numerics", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-numerics.git", + "location" : "https://github.com/apple/swift-numerics", "state" : { "branch" : "main", "revision" : "e30276bff2ff5ed80566fbdca49f50aa160b0e83" @@ -292,7 +292,7 @@ { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { "revision" : "4c6cc0a3b9e8f14b3ae2307c5ccae4de6167ac2c", "version" : "600.0.0-prerelease-2024-06-12"