Skip to content

Commit 3bfa3b6

Browse files
authored
fix remove service (#363)
* fix service deletion * fix AccumulateTests * add tests * commit tests * add littleendian
1 parent 7517701 commit 3bfa3b6

File tree

28 files changed

+2373
-8
lines changed

28 files changed

+2373
-8
lines changed

Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public struct AccountChanges: Sendable {
142142
case let .newAccount(index, account):
143143
try await accounts.addNew(serviceAccount: index, account: account)
144144
case let .removeAccount(index):
145-
accounts.remove(serviceAccount: index)
145+
try await accounts.remove(serviceAccount: index)
146146
case let .updateAccount(index, account):
147147
accounts.set(serviceAccount: index, account: account)
148148
case let .updateStorage(index, key, value):

Blockchain/Sources/Blockchain/State/ServiceAccounts.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public protocol ServiceAccounts: Sendable {
2020
length: UInt32,
2121
value: StateKeys.ServiceAccountPreimageInfoKey.Value?
2222
) async throws
23+
24+
mutating func remove(serviceAccount index: ServiceIndex) async throws
2325
}
2426

2527
public class ServiceAccountsRef: Ref<ServiceAccounts>, @unchecked Sendable {}
@@ -83,8 +85,8 @@ public class ServiceAccountsMutRef: @unchecked Sendable {
8385
changes.addNewAccount(index: index, account: account)
8486
}
8587

86-
public func remove(serviceAccount index: ServiceIndex) {
87-
ref.value.set(serviceAccount: index, account: nil)
88+
public func remove(serviceAccount index: ServiceIndex) async throws {
89+
try await ref.value.remove(serviceAccount: index)
8890
changes.addRemovedAccount(index: index)
8991
}
9092

Blockchain/Sources/Blockchain/State/State.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,24 @@ extension State: ServiceAccounts {
461461
// update value
462462
layer[serviceAccount: index, preimageHash: hash, length: length] = value
463463
}
464+
465+
// TODO: consider if keeping track of service keys at backend level is better
466+
public mutating func remove(serviceAccount index: ServiceIndex) async throws {
467+
layer[serviceAccount: index] = nil
468+
469+
let serviceByte = UInt8(index & 0xFF)
470+
var startKeyData = Data(repeating: 0, count: 31)
471+
startKeyData[0] = serviceByte
472+
let startKey = Data31(startKeyData)!
473+
474+
let candidateKeys = try await backend.getKeys(Data([serviceByte]), startKey, nil)
475+
476+
for (keyData, _) in candidateKeys {
477+
if let key = Data31(keyData), StateKeys.isServiceKey(key, serviceIndex: index) {
478+
layer[key] = nil
479+
}
480+
}
481+
}
464482
}
465483

466484
extension State: Safrole {

Blockchain/Sources/Blockchain/State/StateKeys.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private func constructKey(_ idx: UInt8) -> Data31 {
2424
private func constructKey(_ idx: UInt8, _ service: ServiceIndex) -> Data31 {
2525
var data = Data(repeating: 0, count: 31)
2626
data[0] = idx
27-
withUnsafeBytes(of: service) { ptr in
27+
withUnsafeBytes(of: service.littleEndian) { ptr in
2828
data[1] = ptr.load(as: UInt8.self)
2929
data[3] = ptr.load(fromByteOffset: 1, as: UInt8.self)
3030
data[5] = ptr.load(fromByteOffset: 2, as: UInt8.self)
@@ -40,7 +40,7 @@ private func constructKey(_ service: ServiceIndex, _ val: UInt32, _ data: Data)
4040
let h = valEncoded + data
4141
let a = h.blake2b256hash().data[relative: 0 ..< 27]
4242

43-
withUnsafeBytes(of: service) { servicePtr in
43+
withUnsafeBytes(of: service.littleEndian) { servicePtr in
4444
a.withUnsafeBytes { aPtr in
4545
stateKey.append(servicePtr.load(as: UInt8.self))
4646
stateKey.append(aPtr.load(as: UInt8.self))
@@ -335,3 +335,24 @@ public enum StateKeys {
335335
}
336336
}
337337
}
338+
339+
extension StateKeys {
340+
public static func isServiceKey(_ key: Data31, serviceIndex: ServiceIndex) -> Bool {
341+
let keyData = key.data
342+
let serviceBytes = withUnsafeBytes(of: serviceIndex.littleEndian) { Data($0) }
343+
344+
// service details
345+
if keyData[relative: 0] == 255 {
346+
return keyData[relative: 1] == serviceBytes[relative: 0] &&
347+
keyData[relative: 3] == serviceBytes[relative: 1] &&
348+
keyData[relative: 5] == serviceBytes[relative: 2] &&
349+
keyData[relative: 7] == serviceBytes[relative: 3]
350+
}
351+
352+
// other service keys
353+
return keyData[relative: 0] == serviceBytes[relative: 0] &&
354+
keyData[relative: 2] == serviceBytes[relative: 1] &&
355+
keyData[relative: 4] == serviceBytes[relative: 2] &&
356+
keyData[relative: 6] == serviceBytes[relative: 3]
357+
}
358+
}

Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,7 @@ public class Eject: HostCall {
11301130
// accumulating service definitely exist
11311131
var destAccount = try await x.state.accounts.value.get(serviceAccount: x.serviceIndex)!
11321132
destAccount.balance += ejectAccount!.balance
1133-
x.state.accounts.remove(serviceAccount: ejectIndex)
1133+
try await x.state.accounts.remove(serviceAccount: ejectIndex)
11341134
x.state.accounts.set(serviceAccount: x.serviceIndex, account: destAccount)
11351135
state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.OK.rawValue)
11361136
} else {

JAMTests/Tests/JAMTests/jamtestnet/FuzzTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ struct FuzzTests {
5656
// example: ("0.7.0/1754982630", "00000004")
5757
],
5858
expectFailure: [
59+
("0.7.0/1756790723", "00000011"),
60+
("0.7.0/1756791458", "00000041"),
61+
("0.7.0/1756814312", "00000025"),
62+
("0.7.0/1756792661", "00000027"),
5963
],
6064
ignore: [
61-
("0.7.0/1756548583", "00000009"), // TODO: one storage / preimage mismatch
62-
("0.7.0/1756548706", "00000094"), // TODO: backend
65+
("0.7.0/1756548583", "00000009"), // TODO: hard
6366
]
6467
))
6568
func v070(_ input: TestInput) async throws {

JAMTests/Tests/JAMTests/jamtestnet/TraceTest.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ enum TraceTest {
5454
)
5555
}
5656

57+
// make sure we don't have extra keys
58+
let allKeys = try await stateRef.value.backend.getKeys(nil, nil, nil)
59+
for (key, _) in allKeys {
60+
let data31 = Data31(key)!
61+
#expect(expectedStateDict[data31] != nil, "extra key in boka post state: \(data31.toHexString())")
62+
}
63+
5764
let stateRoot = await stateRef.value.stateRoot
5865
#expect(stateRoot == testcase.postState.root)
5966
case .failure:

JAMTests/Tests/JAMTests/w3f/AccumulateTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ private struct FullAccumulateState: Accumulation {
164164
// update value
165165
preimageInfo[index, default: [:]][hash] = value
166166
}
167+
168+
mutating func remove(serviceAccount index: ServiceIndex) async throws {
169+
accounts[index] = nil
170+
storages[index] = nil
171+
preimages[index] = nil
172+
preimageInfo[index] = nil
173+
}
167174
}
168175

169176
struct AccumulateTests {
348 KB
Binary file not shown.

JAMTests/fuzz/0.7.0/1756790723/00000010.json

Lines changed: 205 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)