Skip to content

Commit 84f08ea

Browse files
authored
0.6.2 updates (#297)
1 parent 9ecbae8 commit 84f08ea

File tree

9 files changed

+338
-241
lines changed

9 files changed

+338
-241
lines changed

Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public final class Runtime {
190190
throw Error.authorizationError(error)
191191
}
192192

193-
try await updatePreimages(block: block, state: &newState, prevState: prevState)
193+
try await updatePreimages(block: block, state: &newState)
194194

195195
newState.activityStatistics = try prevState.value.update(
196196
config: config,
@@ -342,8 +342,8 @@ public final class Runtime {
342342
return availableReports
343343
}
344344

345-
public func updatePreimages(block: BlockRef, state newState: inout State, prevState: StateRef) async throws {
346-
let res = try await prevState.value.updatePreimages(
345+
public func updatePreimages(block: BlockRef, state newState: inout State) async throws {
346+
let res = try await newState.updatePreimages(
347347
config: config, timeslot: newState.timeslot, preimages: block.extrinsic.preimages
348348
)
349349
newState.mergeWith(postState: res)

Blockchain/Sources/Blockchain/VMInvocations/Error.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ public enum VMInvocationsError: Error {
33
case checkMaxDepthLimit
44
case checkIndexTooSmall
55
case forceHalt
6+
case panic
67
}

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

Lines changed: 252 additions & 182 deletions
Large diffs are not rendered by default.

Blockchain/Sources/Blockchain/VMInvocations/HostCall/ResultConstants.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ public enum HostCallResultCode: UInt64 {
33
case NONE = 0xFFFF_FFFF_FFFF_FFFF
44
/// WHAT = 2^64 − 2: Name unknown.
55
case WHAT = 0xFFFF_FFFF_FFFF_FFFE
6-
/// OOB = 2^64 − 3: The return value for when a memory index is provided for reading/writing which is not accessible.
6+
/// OOB = 2^64 − 3: The inner pvm memory index provided for reading/writing is not accessible.
77
case OOB = 0xFFFF_FFFF_FFFF_FFFD
88
/// WHO = 2^64 − 4: Index unknown.
99
case WHO = 0xFFFF_FFFF_FFFF_FFFC

Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/RefineContext.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,31 @@ public class RefineContext: InvocationContext {
1919

2020
public let config: ProtocolConfigRef
2121
public var context: ContextType
22-
public let importSegments: [Data4104]
22+
public let importSegments: [[Data4104]]
2323
public let exportSegmentOffset: UInt64
2424
public let service: ServiceIndex
2525
public let serviceAccounts: ServiceAccounts
26-
public let lookupAnchorTimeslot: TimeslotIndex
26+
public let workPackage: WorkPackage
27+
public let authorizerOutput: Data
2728

2829
public init(
2930
config: ProtocolConfigRef,
3031
context: ContextType,
31-
importSegments: [Data4104],
32+
importSegments: [[Data4104]],
3233
exportSegmentOffset: UInt64,
3334
service: ServiceIndex,
3435
serviceAccounts: some ServiceAccounts,
35-
lookupAnchorTimeslot: TimeslotIndex
36+
workPackage: WorkPackage,
37+
authorizerOutput: Data
3638
) {
3739
self.config = config
3840
self.context = context
3941
self.importSegments = importSegments
4042
self.exportSegmentOffset = exportSegmentOffset
4143
self.service = service
4244
self.serviceAccounts = serviceAccounts
43-
self.lookupAnchorTimeslot = lookupAnchorTimeslot
45+
self.workPackage = workPackage
46+
self.authorizerOutput = authorizerOutput
4447
}
4548

4649
public func dispatch(index: UInt32, state: VMState) async -> ExecOutcome {
@@ -52,13 +55,21 @@ public class RefineContext: InvocationContext {
5255
case HistoricalLookup.identifier:
5356
return await HistoricalLookup(
5457
context: context,
55-
service: service,
58+
serviceIndex: service,
5659
serviceAccounts: serviceAccounts,
57-
lookupAnchorTimeslot: lookupAnchorTimeslot
60+
lookupAnchorTimeslot: workPackage.context.lookupAnchor.timeslot
61+
)
62+
.call(config: config, state: state)
63+
case Fetch.identifier:
64+
return await Fetch(
65+
context: context,
66+
serviceAccounts: serviceAccounts,
67+
serviceIndex: service,
68+
workPackage: workPackage,
69+
authorizerOutput: authorizerOutput,
70+
importSegments: importSegments
5871
)
5972
.call(config: config, state: state)
60-
case Import.identifier:
61-
return await Import(context: context, importSegments: importSegments).call(config: config, state: state)
6273
case Export.identifier:
6374
return await Export(context: &context, exportSegmentOffset: exportSegmentOffset).call(config: config, state: state)
6475
case Machine.identifier:

Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,36 @@ public protocol RefineInvocation {
77
func invoke(
88
config: ProtocolConfigRef,
99
serviceAccounts: some ServiceAccounts,
10-
codeHash: Data32,
11-
gas: Gas,
12-
service: ServiceIndex,
13-
workPackageHash: Data32,
14-
workPayload: Data, // y
15-
refinementCtx: RefinementContext, // c
16-
authorizerHash: Data32,
17-
authorizationOutput: Data,
18-
importSegments: [Data4104],
19-
extrinsicDataBlobs: [Data],
10+
/// Index of the work item to be refined
11+
workItemIndex: Int,
12+
/// The work package
13+
workPackage: WorkPackage,
14+
/// The output of the authorizer
15+
authorizerOutput: Data,
16+
/// all work items's import segments
17+
importSegments: [[Data4104]],
18+
/// Export segment offset
2019
exportSegmentOffset: UInt64
2120
) async throws -> (result: Result<Data, WorkResultError>, exports: [Data4104])
2221
}
2322

2423
extension RefineInvocation {
25-
func invoke(
24+
public func invoke(
2625
config: ProtocolConfigRef,
2726
serviceAccounts: some ServiceAccounts,
28-
codeHash: Data32,
29-
gas: Gas,
30-
service: ServiceIndex,
31-
workPackageHash: Data32,
32-
workPayload: Data, // y
33-
refinementCtx: RefinementContext, // c
34-
authorizerHash: Data32,
35-
authorizationOutput: Data,
36-
importSegments: [Data4104],
37-
extrinsicDataBlobs: [Data],
27+
workItemIndex: Int,
28+
workPackage: WorkPackage,
29+
authorizerOutput: Data,
30+
importSegments: [[Data4104]],
3831
exportSegmentOffset: UInt64
3932
) async throws -> (result: Result<Data, WorkResultError>, exports: [Data4104]) {
33+
let workItem = workPackage.workItems[workItemIndex]
34+
let service = workItem.serviceIndex
35+
4036
let codeBlob = try await serviceAccounts.historicalLookup(
4137
serviceAccount: service,
42-
timeslot: refinementCtx.lookupAnchor.timeslot,
43-
preimageHash: codeHash
38+
timeslot: workPackage.context.lookupAnchor.timeslot,
39+
preimageHash: workItem.codeHash
4440
)
4541

4642
guard let codeBlob, try await serviceAccounts.get(serviceAccount: service) != nil else {
@@ -51,30 +47,30 @@ extension RefineInvocation {
5147
return (.failure(.codeTooLarge), [])
5248
}
5349

54-
let argumentData = try JamEncoder.encode(
50+
let argumentData = try await JamEncoder.encode(
5551
service,
56-
workPayload,
57-
workPackageHash,
58-
refinementCtx,
59-
authorizerHash,
60-
authorizationOutput,
61-
extrinsicDataBlobs
52+
workItem.payloadBlob,
53+
workPackage.hash(),
54+
workPackage.context,
55+
workPackage.authorizer(serviceAccounts: serviceAccounts)
6256
)
57+
6358
let ctx = RefineContext(
6459
config: config,
6560
context: (pvms: [:], exports: []),
6661
importSegments: importSegments,
6762
exportSegmentOffset: exportSegmentOffset,
6863
service: service,
6964
serviceAccounts: serviceAccounts,
70-
lookupAnchorTimeslot: refinementCtx.lookupAnchor.timeslot
65+
workPackage: workPackage,
66+
authorizerOutput: authorizerOutput
7167
)
7268

7369
let (exitReason, _, output) = await invokePVM(
7470
config: config,
7571
blob: codeBlob,
7672
pc: 0,
77-
gas: gas,
73+
gas: workItem.refineGasLimit,
7874
argumentData: argumentData,
7975
ctx: ctx
8076
)

Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,13 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {
115115

116116
var exportSegments = [Data4104]()
117117

118+
// TODO: make this lazy, only fetch when needed by PVM
119+
var importSegments = [[Data4104]]()
118120
for item in workPackage.value.workItems {
119-
// TODO: make this lazy. only fetch when needed by PVM
120-
let importSegments = try await dataAvailability.fetchSegment(segments: item.inputs)
121+
try await importSegments.append(dataAvailability.fetchSegment(segments: item.inputs))
122+
}
121123

124+
for (i, item) in workPackage.value.workItems.enumerated() {
122125
// TODO: generated by the work-package builder.
123126
let extrinsicDataBlobs = [Data]()
124127

@@ -127,16 +130,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {
127130
.invoke(
128131
config: config,
129132
serviceAccounts: state.value,
130-
codeHash: workPackage.value.authorizationCodeHash,
131-
gas: item.refineGasLimit,
132-
service: item.serviceIndex,
133-
workPackageHash: packageHash,
134-
workPayload: item.payloadBlob,
135-
refinementCtx: workPackage.value.context,
136-
authorizerHash: authorizerHash,
137-
authorizationOutput: authorizationOutput,
133+
workItemIndex: i,
134+
workPackage: workPackage.value,
135+
authorizerOutput: authorizationOutput,
138136
importSegments: importSegments,
139-
extrinsicDataBlobs: extrinsicDataBlobs,
140137
exportSegmentOffset: UInt64(exportSegmentOffset)
141138
)
142139
// Export -> DA or exportSegmentOffset + outputDataSegmentsCount ?

PolkaVM/Sources/PolkaVM/Instruction.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,21 @@ public class ExecutionContext {
2929
extension Instruction {
3030
public func execute(context: ExecutionContext, skip: UInt32) -> ExecOutcome {
3131
do {
32-
let execRes = try _executeImpl(context: context)
33-
if case .exit = execRes {
34-
return execRes
32+
context.state.isExecutingInst = true
33+
let out1 = try _executeImpl(context: context)
34+
context.state.isExecutingInst = false
35+
if case .exit = out1 {
36+
return out1
3537
}
3638
return updatePC(context: context, skip: skip)
3739
} catch let e as MemoryError {
3840
logger.debug("memory error: \(e)")
41+
context.state.isExecutingInst = false
3942
return .exit(.pageFault(e.address))
4043
} catch let e {
4144
// other unknown errors
4245
logger.error("execution failed!", metadata: ["error": "\(e)"])
46+
context.state.isExecutingInst = false
4347
return .exit(.panic(.trap))
4448
}
4549
}

PolkaVM/Sources/PolkaVM/VMState.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import Utils
55
private let logger = Logger(label: "VMState ")
66

77
public class VMState {
8+
public enum VMError: Error {
9+
case invalidInstructionMemoryAccess
10+
}
11+
812
public let program: ProgramCode
913

1014
public private(set) var pc: UInt32
@@ -13,6 +17,8 @@ public class VMState {
1317
private var gas: GasInt
1418
private var memory: Memory
1519

20+
public var isExecutingInst: Bool = false
21+
1622
public init(program: ProgramCode, pc: UInt32, registers: Registers, gas: Gas, memory: Memory) {
1723
self.program = program
1824
self.pc = pc
@@ -55,13 +61,23 @@ public class VMState {
5561
memory.isReadable(address: UInt32(truncatingIfNeeded: address), length: length)
5662
}
5763

64+
// During the course of executing instructions
65+
// When an index of ram below 2^16 is required, the machine always panics immediately
66+
private func validateAddress(_ address: some FixedWidthInteger) throws {
67+
if isExecutingInst, UInt32(truncatingIfNeeded: address) < (1 << 16) {
68+
throw VMError.invalidInstructionMemoryAccess
69+
}
70+
}
71+
5872
public func readMemory(address: some FixedWidthInteger) throws -> UInt8 {
73+
try validateAddress(address)
5974
let res = try memory.read(address: UInt32(truncatingIfNeeded: address))
6075
logger.trace("read \(address) (\(res))")
6176
return res
6277
}
6378

6479
public func readMemory(address: some FixedWidthInteger, length: Int) throws -> Data {
80+
try validateAddress(address)
6581
let res = try memory.read(address: UInt32(truncatingIfNeeded: address), length: length)
6682
logger.trace("read \(address)..+\(length) (\(res))")
6783
return res
@@ -72,11 +88,13 @@ public class VMState {
7288
}
7389

7490
public func writeMemory(address: some FixedWidthInteger, value: UInt8) throws {
91+
try validateAddress(address)
7592
logger.trace("write \(address) (\(value))")
7693
try memory.write(address: UInt32(truncatingIfNeeded: address), value: value)
7794
}
7895

7996
public func writeMemory(address: some FixedWidthInteger, values: some Sequence<UInt8>) throws {
97+
try validateAddress(address)
8098
logger.trace("write \(address) (\(values))")
8199
try memory.write(address: UInt32(truncatingIfNeeded: address), values: Data(values))
82100
}

0 commit comments

Comments
 (0)