Skip to content

Commit 07b8b47

Browse files
authored
fuzz v1 and fix (#368)
* improve bench * various fix * fix accumulate * add fuzz v1 * fix * fix flaky test * fix
1 parent 0a75453 commit 07b8b47

File tree

21 files changed

+283
-100
lines changed

21 files changed

+283
-100
lines changed

Blockchain/Sources/Blockchain/Blockchain.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public final class Blockchain: ServiceBase, @unchecked Sendable {
4040
try await withSpan("importBlock") { span in
4141
span.attributes.blockHash = block.hash.description
4242

43-
let runtime = Runtime(config: config)
43+
let runtime = try Runtime(config: config, ancestry: .init(config: config))
4444
let parent = try await dataProvider.getState(hash: block.header.parentHash)
4545
let stateRoot = await parent.value.stateRoot
4646
let timeslot = timeProvider.getTime().timeToTimeslot(config: config)

Blockchain/Sources/Blockchain/RuntimeProtocols/AccumulateFunction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public struct AccumulateState: Sendable {
7171

7272
public func copy() -> AccumulateState {
7373
AccumulateState(
74-
accounts: ServiceAccountsMutRef(accounts.value),
74+
accounts: ServiceAccountsMutRef(copying: accounts),
7575
validatorQueue: validatorQueue,
7676
authorizationQueue: authorizationQueue,
7777
manager: manager,

Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,15 @@ extension Accumulation {
275275
logger.debug("[∆*] services to accumulate: \(Array(uniqueServices))")
276276

277277
let serviceBatches = sortServicesToBatches(services: uniqueServices)
278+
logger.debug("[∆*] service batches: \(serviceBatches)")
278279

279280
for serviceBatch in serviceBatches {
280281
logger.debug("[∆*] processing batch: \(serviceBatch)")
281282

282283
let batchState = currentState
283284

285+
batchState.accounts.clearRecordedChanges()
286+
284287
let batchResults = try await withThrowingTaskGroup(
285288
of: (ServiceIndex, AccumulationResult).self,
286289
returning: [(ServiceIndex, AccumulationResult)].self

Blockchain/Sources/Blockchain/RuntimeProtocols/Guaranteeing.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ extension Guaranteeing {
118118
public func update(
119119
config: ProtocolConfigRef,
120120
timeslot: TimeslotIndex,
121-
extrinsic: ExtrinsicGuarantees
121+
extrinsic: ExtrinsicGuarantees,
122+
ancestry: ConfigLimitedSizeArray<AncestryItem, ProtocolConfig.Int0, ProtocolConfig.MaxLookupAnchorAge>?
122123
) async throws(GuaranteeingError) -> (
123124
newReports: ConfigFixedSizeArray<
124125
ReportItem?,
@@ -225,6 +226,17 @@ extension Guaranteeing {
225226
throw .invalidContext
226227
}
227228

229+
if let ancestry {
230+
let lookupTimeslot = UInt32(context.lookupAnchor.timeslot)
231+
let lookupHeaderHash = context.lookupAnchor.headerHash
232+
233+
guard ancestry.array.contains(where: { item in
234+
item.timeslot == lookupTimeslot && item.headerHash == lookupHeaderHash
235+
}) else {
236+
throw .invalidContext
237+
}
238+
}
239+
228240
for prerequisiteWorkPackage in context.prerequisiteWorkPackages.union(report.lookup.keys) {
229241
guard recentWorkPackageHashes.contains(prerequisiteWorkPackage) ||
230242
workPackageHashes.contains(prerequisiteWorkPackage)

Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ import Foundation
33
import TracingUtils
44
import Utils
55

6+
public struct AncestryItem: Codable {
7+
public let timeslot: TimeslotIndex
8+
public let headerHash: Data32
9+
10+
public init(timeslot: TimeslotIndex, headerHash: Data32) {
11+
self.timeslot = timeslot
12+
self.headerHash = headerHash
13+
}
14+
}
15+
616
private let logger = Logger(label: "Runtime")
717

818
// the STF
@@ -40,8 +50,23 @@ public final class Runtime {
4050

4151
public let config: ProtocolConfigRef
4252

43-
public init(config: ProtocolConfigRef) {
53+
// nil means no ancestry tracking and checking
54+
public var ancestry: ConfigLimitedSizeArray<AncestryItem, ProtocolConfig.Int0, ProtocolConfig.MaxLookupAnchorAge>?
55+
56+
public init(
57+
config: ProtocolConfigRef,
58+
ancestry: ConfigLimitedSizeArray<AncestryItem, ProtocolConfig.Int0, ProtocolConfig.MaxLookupAnchorAge>? = nil
59+
) {
4460
self.config = config
61+
self.ancestry = ancestry
62+
}
63+
64+
public func updateAncestry(with block: BlockRef) {
65+
guard var currentAncestry = ancestry else { return }
66+
67+
let newItem = AncestryItem(timeslot: block.header.timeslot, headerHash: block.hash)
68+
currentAncestry.safeAppend(newItem)
69+
ancestry = currentAncestry
4570
}
4671

4772
public func validateHeader(block: Validated<BlockRef>, state: StateRef, context: ApplyContext) throws(Error) {
@@ -233,6 +258,8 @@ public final class Runtime {
233258
throw .other(error)
234259
}
235260

261+
updateAncestry(with: block)
262+
236263
return StateRef(newState)
237264
}
238265

@@ -292,7 +319,7 @@ public final class Runtime {
292319

293320
public func updateReports(block: BlockRef, state newState: inout State) async throws -> [Ed25519PublicKey] {
294321
let result = try await newState.update(
295-
config: config, timeslot: newState.timeslot, extrinsic: block.extrinsic.reports
322+
config: config, timeslot: newState.timeslot, extrinsic: block.extrinsic.reports, ancestry: ancestry
296323
)
297324
newState.reports = result.newReports
298325
return result.reporters

Blockchain/Sources/Blockchain/State/ServiceAccounts.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import Foundation
22
import Utils
33

44
public protocol ServiceAccounts: Sendable {
5+
func copy() -> ServiceAccounts
6+
57
func get(serviceAccount index: ServiceIndex) async throws -> ServiceAccountDetails?
68
func get(serviceAccount index: ServiceIndex, storageKey key: Data) async throws -> Data?
79
func get(serviceAccount index: ServiceIndex, preimageHash hash: Data32) async throws -> Data?
@@ -37,6 +39,11 @@ public class ServiceAccountsMutRef: @unchecked Sendable {
3739
changes = AccountChanges()
3840
}
3941

42+
public init(copying other: ServiceAccountsMutRef) {
43+
ref = RefMut(other.ref.value.copy())
44+
changes = other.changes
45+
}
46+
4047
public func toRef() -> ServiceAccountsRef {
4148
ServiceAccountsRef(ref.value)
4249
}

Blockchain/Sources/Blockchain/State/State.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ public struct State: Sendable {
1616
self.layer = layer
1717
}
1818

19+
public init(copying other: State) {
20+
// backend can be shared as it's read-only until end of stf
21+
backend = other.backend
22+
layer = StateLayer(copying: other.layer)
23+
}
24+
1925
// α: The core αuthorizations pool.
2026
public var coreAuthorizationPool: StateKeys.CoreAuthorizationPoolKey.Value {
2127
get {
@@ -344,6 +350,10 @@ extension State: Dummy {
344350
}
345351

346352
extension State: ServiceAccounts {
353+
public func copy() -> ServiceAccounts {
354+
State(copying: self)
355+
}
356+
347357
public func get(serviceAccount index: ServiceIndex) async throws -> ServiceAccountDetails? {
348358
if layer.isDeleted(serviceAccount: index) {
349359
return nil

Blockchain/Sources/Blockchain/State/StateLayer.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ public struct StateLayer: Sendable {
4545
}
4646
}
4747

48+
public init(copying other: StateLayer) {
49+
changes = other.changes
50+
}
51+
4852
// α: The core αuthorizations pool.
4953
public var coreAuthorizationPool: StateKeys.CoreAuthorizationPoolKey.Value {
5054
get {

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

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -797,16 +797,19 @@ public class Bless: HostCall {
797797
var alwaysAcc: [ServiceIndex: Gas]?
798798
let length = 12 * Int(regs[4])
799799
if state.isMemoryReadable(address: regs[3], length: length) {
800-
alwaysAcc = [:]
801800
let data = try state.readMemory(address: regs[3], length: length)
802801
for i in stride(from: 0, to: length, by: 12) {
803802
let serviceIndex = ServiceIndex(data[i ..< i + 4].decode(UInt32.self))
804803
let gas = Gas(data[i + 4 ..< i + 12].decode(UInt64.self))
805-
alwaysAcc![serviceIndex] = gas
804+
if alwaysAcc != nil {
805+
alwaysAcc![serviceIndex] = gas
806+
} else {
807+
alwaysAcc = [serviceIndex: gas]
808+
}
806809
}
807810
}
808811

809-
if alwaysAcc == nil, assigners == nil {
812+
if alwaysAcc == nil || assigners == nil {
810813
throw VMInvocationsError.panic
811814
} else if x.serviceIndex != x.state.manager {
812815
state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.HUH.rawValue)
@@ -845,9 +848,11 @@ public class Assign: HostCall {
845848
var authorizationQueue: [Data32]?
846849
let length = 32 * config.value.maxAuthorizationsQueueItems
847850
if state.isMemoryReadable(address: startAddr, length: length) {
848-
authorizationQueue = [Data32]()
849851
let data = try state.readMemory(address: startAddr, length: length)
850852
for i in stride(from: 0, to: length, by: 32) {
853+
if authorizationQueue == nil {
854+
authorizationQueue = [Data32]()
855+
}
851856
authorizationQueue!.append(Data32(data[i ..< i + 32])!)
852857
}
853858
}
@@ -886,9 +891,11 @@ public class Designate: HostCall {
886891
var validatorQueue: [ValidatorKey]?
887892
let length = 336 * config.value.totalNumberOfValidators
888893
if state.isMemoryReadable(address: startAddr, length: length) {
889-
validatorQueue = [ValidatorKey]()
890894
let data = try state.readMemory(address: startAddr, length: length)
891895
for i in stride(from: 0, to: length, by: 336) {
896+
if validatorQueue == nil {
897+
validatorQueue = [ValidatorKey]()
898+
}
892899
try validatorQueue!.append(ValidatorKey(data: Data(data[i ..< i + 336])))
893900
}
894901
}
@@ -921,7 +928,7 @@ public class Checkpoint: HostCall {
921928
state.writeRegister(Registers.Index(raw: 7), UInt64(bitPattern: state.getGas().value))
922929

923930
y.serviceIndex = x.serviceIndex
924-
y.state = x.state
931+
y.state = x.state.copy()
925932
y.nextAccountIndex = x.nextAccountIndex
926933
y.transfers = x.transfers
927934
y.yield = x.yield

Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/AccumulateContext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public final class AccumulateContext: InvocationContext {
8181
return await Log(service: context.x.serviceIndex).call(config: config, state: state)
8282
default:
8383
state.consumeGas(Gas(10))
84-
state.writeRegister(Registers.Index(raw: 0), HostCallResultCode.WHAT.rawValue)
84+
state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.WHAT.rawValue)
8585
return .continued
8686
}
8787
}

0 commit comments

Comments
 (0)