Skip to content

Commit

Permalink
0.6.2 updates (#297)
Browse files Browse the repository at this point in the history
  • Loading branch information
qiweiii authored Feb 19, 2025
1 parent 9ecbae8 commit 84f08ea
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 241 deletions.
6 changes: 3 additions & 3 deletions Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public final class Runtime {
throw Error.authorizationError(error)
}

try await updatePreimages(block: block, state: &newState, prevState: prevState)
try await updatePreimages(block: block, state: &newState)

newState.activityStatistics = try prevState.value.update(
config: config,
Expand Down Expand Up @@ -342,8 +342,8 @@ public final class Runtime {
return availableReports
}

public func updatePreimages(block: BlockRef, state newState: inout State, prevState: StateRef) async throws {
let res = try await prevState.value.updatePreimages(
public func updatePreimages(block: BlockRef, state newState: inout State) async throws {
let res = try await newState.updatePreimages(
config: config, timeslot: newState.timeslot, preimages: block.extrinsic.preimages
)
newState.mergeWith(postState: res)
Expand Down
1 change: 1 addition & 0 deletions Blockchain/Sources/Blockchain/VMInvocations/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ public enum VMInvocationsError: Error {
case checkMaxDepthLimit
case checkIndexTooSmall
case forceHalt
case panic
}
434 changes: 252 additions & 182 deletions Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ public enum HostCallResultCode: UInt64 {
case NONE = 0xFFFF_FFFF_FFFF_FFFF
/// WHAT = 2^64 − 2: Name unknown.
case WHAT = 0xFFFF_FFFF_FFFF_FFFE
/// OOB = 2^64 − 3: The return value for when a memory index is provided for reading/writing which is not accessible.
/// OOB = 2^64 − 3: The inner pvm memory index provided for reading/writing is not accessible.
case OOB = 0xFFFF_FFFF_FFFF_FFFD
/// WHO = 2^64 − 4: Index unknown.
case WHO = 0xFFFF_FFFF_FFFF_FFFC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,31 @@ public class RefineContext: InvocationContext {

public let config: ProtocolConfigRef
public var context: ContextType
public let importSegments: [Data4104]
public let importSegments: [[Data4104]]
public let exportSegmentOffset: UInt64
public let service: ServiceIndex
public let serviceAccounts: ServiceAccounts
public let lookupAnchorTimeslot: TimeslotIndex
public let workPackage: WorkPackage
public let authorizerOutput: Data

public init(
config: ProtocolConfigRef,
context: ContextType,
importSegments: [Data4104],
importSegments: [[Data4104]],
exportSegmentOffset: UInt64,
service: ServiceIndex,
serviceAccounts: some ServiceAccounts,
lookupAnchorTimeslot: TimeslotIndex
workPackage: WorkPackage,
authorizerOutput: Data
) {
self.config = config
self.context = context
self.importSegments = importSegments
self.exportSegmentOffset = exportSegmentOffset
self.service = service
self.serviceAccounts = serviceAccounts
self.lookupAnchorTimeslot = lookupAnchorTimeslot
self.workPackage = workPackage
self.authorizerOutput = authorizerOutput
}

public func dispatch(index: UInt32, state: VMState) async -> ExecOutcome {
Expand All @@ -52,13 +55,21 @@ public class RefineContext: InvocationContext {
case HistoricalLookup.identifier:
return await HistoricalLookup(
context: context,
service: service,
serviceIndex: service,
serviceAccounts: serviceAccounts,
lookupAnchorTimeslot: lookupAnchorTimeslot
lookupAnchorTimeslot: workPackage.context.lookupAnchor.timeslot
)
.call(config: config, state: state)
case Fetch.identifier:
return await Fetch(
context: context,
serviceAccounts: serviceAccounts,
serviceIndex: service,
workPackage: workPackage,
authorizerOutput: authorizerOutput,
importSegments: importSegments
)
.call(config: config, state: state)
case Import.identifier:
return await Import(context: context, importSegments: importSegments).call(config: config, state: state)
case Export.identifier:
return await Export(context: &context, exportSegmentOffset: exportSegmentOffset).call(config: config, state: state)
case Machine.identifier:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,36 @@ public protocol RefineInvocation {
func invoke(
config: ProtocolConfigRef,
serviceAccounts: some ServiceAccounts,
codeHash: Data32,
gas: Gas,
service: ServiceIndex,
workPackageHash: Data32,
workPayload: Data, // y
refinementCtx: RefinementContext, // c
authorizerHash: Data32,
authorizationOutput: Data,
importSegments: [Data4104],
extrinsicDataBlobs: [Data],
/// Index of the work item to be refined
workItemIndex: Int,
/// The work package
workPackage: WorkPackage,
/// The output of the authorizer
authorizerOutput: Data,
/// all work items's import segments
importSegments: [[Data4104]],
/// Export segment offset
exportSegmentOffset: UInt64
) async throws -> (result: Result<Data, WorkResultError>, exports: [Data4104])
}

extension RefineInvocation {
func invoke(
public func invoke(
config: ProtocolConfigRef,
serviceAccounts: some ServiceAccounts,
codeHash: Data32,
gas: Gas,
service: ServiceIndex,
workPackageHash: Data32,
workPayload: Data, // y
refinementCtx: RefinementContext, // c
authorizerHash: Data32,
authorizationOutput: Data,
importSegments: [Data4104],
extrinsicDataBlobs: [Data],
workItemIndex: Int,
workPackage: WorkPackage,
authorizerOutput: Data,
importSegments: [[Data4104]],
exportSegmentOffset: UInt64
) async throws -> (result: Result<Data, WorkResultError>, exports: [Data4104]) {
let workItem = workPackage.workItems[workItemIndex]
let service = workItem.serviceIndex

let codeBlob = try await serviceAccounts.historicalLookup(
serviceAccount: service,
timeslot: refinementCtx.lookupAnchor.timeslot,
preimageHash: codeHash
timeslot: workPackage.context.lookupAnchor.timeslot,
preimageHash: workItem.codeHash
)

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

let argumentData = try JamEncoder.encode(
let argumentData = try await JamEncoder.encode(
service,
workPayload,
workPackageHash,
refinementCtx,
authorizerHash,
authorizationOutput,
extrinsicDataBlobs
workItem.payloadBlob,
workPackage.hash(),
workPackage.context,
workPackage.authorizer(serviceAccounts: serviceAccounts)
)

let ctx = RefineContext(
config: config,
context: (pvms: [:], exports: []),
importSegments: importSegments,
exportSegmentOffset: exportSegmentOffset,
service: service,
serviceAccounts: serviceAccounts,
lookupAnchorTimeslot: refinementCtx.lookupAnchor.timeslot
workPackage: workPackage,
authorizerOutput: authorizerOutput
)

let (exitReason, _, output) = await invokePVM(
config: config,
blob: codeBlob,
pc: 0,
gas: gas,
gas: workItem.refineGasLimit,
argumentData: argumentData,
ctx: ctx
)
Expand Down
19 changes: 8 additions & 11 deletions Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,13 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {

var exportSegments = [Data4104]()

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

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

Expand All @@ -127,16 +130,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {
.invoke(
config: config,
serviceAccounts: state.value,
codeHash: workPackage.value.authorizationCodeHash,
gas: item.refineGasLimit,
service: item.serviceIndex,
workPackageHash: packageHash,
workPayload: item.payloadBlob,
refinementCtx: workPackage.value.context,
authorizerHash: authorizerHash,
authorizationOutput: authorizationOutput,
workItemIndex: i,
workPackage: workPackage.value,
authorizerOutput: authorizationOutput,
importSegments: importSegments,
extrinsicDataBlobs: extrinsicDataBlobs,
exportSegmentOffset: UInt64(exportSegmentOffset)
)
// Export -> DA or exportSegmentOffset + outputDataSegmentsCount ?
Expand Down
10 changes: 7 additions & 3 deletions PolkaVM/Sources/PolkaVM/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,21 @@ public class ExecutionContext {
extension Instruction {
public func execute(context: ExecutionContext, skip: UInt32) -> ExecOutcome {
do {
let execRes = try _executeImpl(context: context)
if case .exit = execRes {
return execRes
context.state.isExecutingInst = true
let out1 = try _executeImpl(context: context)
context.state.isExecutingInst = false
if case .exit = out1 {
return out1
}
return updatePC(context: context, skip: skip)
} catch let e as MemoryError {
logger.debug("memory error: \(e)")
context.state.isExecutingInst = false
return .exit(.pageFault(e.address))
} catch let e {
// other unknown errors
logger.error("execution failed!", metadata: ["error": "\(e)"])
context.state.isExecutingInst = false
return .exit(.panic(.trap))
}
}
Expand Down
18 changes: 18 additions & 0 deletions PolkaVM/Sources/PolkaVM/VMState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import Utils
private let logger = Logger(label: "VMState ")

public class VMState {
public enum VMError: Error {
case invalidInstructionMemoryAccess
}

public let program: ProgramCode

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

public var isExecutingInst: Bool = false

public init(program: ProgramCode, pc: UInt32, registers: Registers, gas: Gas, memory: Memory) {
self.program = program
self.pc = pc
Expand Down Expand Up @@ -55,13 +61,23 @@ public class VMState {
memory.isReadable(address: UInt32(truncatingIfNeeded: address), length: length)
}

// During the course of executing instructions
// When an index of ram below 2^16 is required, the machine always panics immediately
private func validateAddress(_ address: some FixedWidthInteger) throws {
if isExecutingInst, UInt32(truncatingIfNeeded: address) < (1 << 16) {
throw VMError.invalidInstructionMemoryAccess
}
}

public func readMemory(address: some FixedWidthInteger) throws -> UInt8 {
try validateAddress(address)
let res = try memory.read(address: UInt32(truncatingIfNeeded: address))
logger.trace("read \(address) (\(res))")
return res
}

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

public func writeMemory(address: some FixedWidthInteger, value: UInt8) throws {
try validateAddress(address)
logger.trace("write \(address) (\(value))")
try memory.write(address: UInt32(truncatingIfNeeded: address), value: value)
}

public func writeMemory(address: some FixedWidthInteger, values: some Sequence<UInt8>) throws {
try validateAddress(address)
logger.trace("write \(address) (\(values))")
try memory.write(address: UInt32(truncatingIfNeeded: address), values: Data(values))
}
Expand Down

0 comments on commit 84f08ea

Please sign in to comment.