Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update pvm tests #271

Merged
merged 17 commits into from
Feb 12, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -859,10 +859,9 @@
var segment: Data?
if context.pvms[regs[0]] == nil {
segment = Data()
} else if state.isMemoryWritable(address: regs[1], length: Int(regs[3])), context.pvms[regs[0]]!.memory.isReadable(
address: UInt32(truncatingIfNeeded: regs[2]),
length: Int(regs[3])
) {
} else if state.isMemoryWritable(address: regs[1], length: Int(regs[3])),
context.pvms[regs[0]]!.memory.isReadable(address: UInt32(truncatingIfNeeded: regs[2]), length: Int(regs[3]))
{

Check warning on line 864 in Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift

View check run for this annotation

Codecov / codecov/patch

Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift#L862-L864

Added lines #L862 - L864 were not covered by tests
segment = try context.pvms[regs[0]]!.memory.read(address: UInt32(truncatingIfNeeded: regs[2]), length: Int(regs[3]))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ private let logger = Logger(label: "RefineContext")

public struct InnerPvm {
public var code: Data
public var memory: Memory
public var memory: GeneralMemory
public var pc: UInt32
}

Expand Down
89 changes: 49 additions & 40 deletions JAMTests/Tests/JAMTests/PVMTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,25 @@ struct MemoryChunk: Codable {
}

enum Status: String, Codable {
case trap
case panic
case halt
case pageFault = "page-fault"
}

struct PolkaVMTestcase: Codable, CustomStringConvertible {
var name: String
var initialRegs: [UInt32]
var initialRegs: [UInt64]
var initialPC: UInt32
var initialPageMap: [PageMap]
var initialMemory: [MemoryChunk]
var initialGas: Gas
var program: [UInt8]
var expectedStatus: Status
var expectedRegs: [UInt32]
var expectedRegs: [UInt64]
var expectedPC: UInt32
var expectedMemory: [MemoryChunk]
var expectedGas: GasInt
var expectedPageFaultAddress: UInt32?

enum CodingKeys: String, CodingKey {
case name
Expand All @@ -55,6 +57,7 @@ struct PolkaVMTestcase: Codable, CustomStringConvertible {
case expectedPC = "expected-pc"
case expectedMemory = "expected-memory"
case expectedGas = "expected-gas"
case expectedPageFaultAddress = "expected-page-fault-address"
}

var description: String {
Expand All @@ -65,49 +68,55 @@ struct PolkaVMTestcase: Codable, CustomStringConvertible {
private let logger = Logger(label: "PVMTests")

struct PVMTests {
init() {
setupTestLogger()
}
// init() {
// setupTestLogger()
// }

static func loadTests() throws -> [Testcase] {
try TestLoader.getTestcases(path: "pvm/programs", extension: "json")
}

@Test(arguments: try loadTests())
func testPVM(testCase _: Testcase) async throws {
// let decoder = JSONDecoder()
// let testCase = try decoder.decode(PolkaVMTestcase.self, from: testCase.data)
// let program = try ProgramCode(Data(testCase.program))
// let memory = Memory(
// pageMap: testCase.initialPageMap.map { (address: $0.address, length: $0.length, writable: $0.isWritable) },
// chunks: testCase.initialMemory.map { (address: $0.address, data: Data($0.contents)) }
// )
// let vmState = VMState(
// program: program,
// pc: testCase.initialPC,
// registers: Registers(testCase.initialRegs),
// gas: testCase.initialGas,
// memory: memory
// )
// let engine = Engine(config: DefaultPvmConfig())
// let exitReason = await engine.execute(program: program, state: vmState)
// logger.debug("exit reason: \(exitReason)")
// let exitReason2: Status = switch exitReason {
// case .halt:
// .halt
// default:
// .trap
// }
func testPVM(testCase: Testcase) async throws {
let decoder = JSONDecoder()
let testCase = try decoder.decode(PolkaVMTestcase.self, from: testCase.data)
let program = try ProgramCode(Data(testCase.program))
let memory = try GeneralMemory(
pageMap: testCase.initialPageMap.map { (address: $0.address, length: $0.length, writable: $0.isWritable) },
chunks: testCase.initialMemory.map { (address: $0.address, data: Data($0.contents)) }
)
let vmState = VMState(
program: program,
pc: testCase.initialPC,
registers: Registers(testCase.initialRegs),
gas: testCase.initialGas,
memory: memory
)
let engine = Engine(config: DefaultPvmConfig())
let exitReason = await engine.execute(state: vmState)
logger.debug("exit reason: \(exitReason)")
var pageFaultAddress: UInt32?
var status: Status
switch exitReason {
case .halt:
status = .halt
case let .pageFault(addr):
pageFaultAddress = addr
status = .pageFault
default:
status = .panic
}

// #expect(exitReason2 == testCase.expectedStatus)
// #expect(vmState.getRegisters() == Registers(testCase.expectedRegs))
// #expect(vmState.pc == testCase.expectedPC)
// for chunk in testCase.expectedMemory {
// for (offset, byte) in chunk.contents.enumerated() {
// let value = try vmState.getMemory().read(address: chunk.address + UInt32(offset))
// #expect(value == byte)
// }
// }
// #expect(vmState.getGas() == testCase.expectedGas)
#expect(status == testCase.expectedStatus)
#expect(vmState.getRegisters() == Registers(testCase.expectedRegs))
#expect(vmState.pc == testCase.expectedPC)
#expect(pageFaultAddress == testCase.expectedPageFaultAddress)
for chunk in testCase.expectedMemory {
for (offset, byte) in chunk.contents.enumerated() {
let value = try vmState.getMemory().read(address: chunk.address + UInt32(offset))
#expect(value == byte)
}
}
#expect(vmState.getGas() == testCase.expectedGas)
}
}
2 changes: 1 addition & 1 deletion JAMTests/jamtestvectors
Submodule jamtestvectors updated 315 files
8 changes: 4 additions & 4 deletions PolkaVM/Sources/PolkaVM/Engine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import TracingUtils
import Utils

private let logger = Logger(label: "Engine")
private let logger = Logger(label: "Engine ")

public class Engine {
let config: PvmConfig
Expand Down Expand Up @@ -59,20 +59,20 @@ public class Engine {
func step(program: ProgramCode, context: ExecutionContext) -> ExecOutcome {
let pc = context.state.pc
let skip = program.skip(pc)
logger.trace("======== pc(\(pc)) skip(\(skip)) =========")

let inst = program.getInstructionAt(pc: pc)

guard let inst else {
return .exit(.panic(.invalidInstructionIndex))
}

// TODO: check after GP specified the behavior
if context.state.program.basicBlockIndices.contains(pc) {
let blockGas = context.state.program.getBlockGasCosts(pc: pc)
context.state.consumeGas(blockGas)
logger.debug("consumed \(blockGas) gas for block at pc: \(pc)")
}

logger.debug("executing \(inst)", metadata: ["skip": "\(skip)", "pc": "\(context.state.pc)"])
logger.trace("exec \(inst)")

return inst.execute(context: context, skip: skip)
}
Expand Down
1 change: 0 additions & 1 deletion PolkaVM/Sources/PolkaVM/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ extension Instruction {
if case .exit = execRes {
return execRes
}
logger.debug("execution success! updating pc...")
return updatePC(context: context, skip: skip)
} catch let e as MemoryError {
logger.debug("memory error: \(e)")
Expand Down
58 changes: 34 additions & 24 deletions PolkaVM/Sources/PolkaVM/InstructionTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ public class InstructionTable {
Instructions.Trap.self,
Instructions.Fallthrough.self,
Instructions.Ecalli.self,
Instructions.LoadImm64.self,
Instructions.StoreImmU8.self,
Instructions.StoreImmU16.self,
Instructions.StoreImmU32.self,
Instructions.StoreImmU64.self,
Instructions.Jump.self,
Instructions.JumpInd.self,
Instructions.LoadImm.self,
Expand All @@ -21,12 +23,16 @@ public class InstructionTable {
Instructions.LoadU16.self,
Instructions.LoadI16.self,
Instructions.LoadU32.self,
Instructions.LoadI32.self,
Instructions.LoadU64.self,
Instructions.StoreU8.self,
Instructions.StoreU16.self,
Instructions.StoreU32.self,
Instructions.StoreU64.self,
Instructions.StoreImmIndU8.self,
Instructions.StoreImmIndU16.self,
Instructions.StoreImmIndU32.self,
Instructions.StoreImmIndU64.self,
Instructions.LoadImmJump.self,
Instructions.BranchEqImm.self,
Instructions.BranchNeImm.self,
Expand All @@ -44,45 +50,50 @@ public class InstructionTable {
Instructions.CountSetBits32.self,
Instructions.LeadingZeroBits64.self,
Instructions.LeadingZeroBits32.self,
Instructions.TrailingZeroBits64.self,
Instructions.TrailingZeroBits32.self,
Instructions.SignExtend8.self,
Instructions.SignExtend16.self,
Instructions.ZeroExtend16.self,
Instructions.ReverseBytes.self,
Instructions.StoreIndU8.self,
Instructions.StoreIndU16.self,
Instructions.StoreIndU32.self,
Instructions.StoreIndU64.self,
Instructions.LoadIndU8.self,
Instructions.LoadIndI8.self,
Instructions.LoadIndU16.self,
Instructions.LoadIndI16.self,
Instructions.LoadIndU32.self,
Instructions.LoadIndI32.self,
Instructions.LoadIndU64.self,
Instructions.AddImm32.self,
Instructions.AddImm64.self,
Instructions.AndImm.self,
Instructions.XorImm.self,
Instructions.OrImm.self,
Instructions.MulImm32.self,
Instructions.MulImm64.self,
Instructions.SetLtUImm.self,
Instructions.SetLtSImm.self,
Instructions.ShloLImm32.self,
Instructions.ShloLImm64.self,
Instructions.ShloRImm32.self,
Instructions.ShloRImm64.self,
Instructions.SharRImm32.self,
Instructions.SharRImm64.self,
Instructions.NegAddImm32.self,
Instructions.NegAddImm64.self,
Instructions.SetGtUImm.self,
Instructions.SetGtSImm.self,
Instructions.ShloLImmAlt32.self,
Instructions.ShloRImmAlt32.self,
Instructions.SharRImmAlt32.self,
Instructions.CmovIzImm.self,
Instructions.CmovNzImm.self,
Instructions.AddImm64.self,
Instructions.MulImm64.self,
Instructions.ShloLImm64.self,
Instructions.ShloRImm64.self,
Instructions.SharRImm64.self,
Instructions.NegAddImm64.self,
Instructions.ShloLImmAlt64.self,
Instructions.ShloRImmAlt64.self,
Instructions.SharRImmAlt64.self,
Instructions.CmovIzImm.self,
Instructions.CmovNzImm.self,
Instructions.RotR64Imm.self,
Instructions.RotR64ImmAlt.self,
Instructions.RotR32Imm.self,
Expand All @@ -96,32 +107,32 @@ public class InstructionTable {
Instructions.LoadImmJumpInd.self,
Instructions.Add32.self,
Instructions.Sub32.self,
Instructions.Add64.self,
Instructions.Sub64.self,
Instructions.And.self,
Instructions.Xor.self,
Instructions.Or.self,
Instructions.Mul32.self,
Instructions.Mul64.self,
Instructions.MulUpperSS.self,
Instructions.MulUpperUU.self,
Instructions.MulUpperSU.self,
Instructions.DivU32.self,
Instructions.DivU64.self,
Instructions.DivS32.self,
Instructions.DivS64.self,
Instructions.RemU32.self,
Instructions.RemU64.self,
Instructions.RemS32.self,
Instructions.RemS64.self,
Instructions.SetLtU.self,
Instructions.SetLtS.self,
Instructions.ShloL32.self,
Instructions.ShloR32.self,
Instructions.SharR32.self,
Instructions.Add64.self,
Instructions.Sub64.self,
Instructions.Mul64.self,
Instructions.DivU64.self,
Instructions.DivS64.self,
Instructions.RemU64.self,
Instructions.RemS64.self,
Instructions.ShloL64.self,
Instructions.ShloR64.self,
Instructions.SharR64.self,
Instructions.And.self,
Instructions.Xor.self,
Instructions.Or.self,
Instructions.MulUpperSS.self,
Instructions.MulUpperUU.self,
Instructions.MulUpperSU.self,
Instructions.SetLtU.self,
Instructions.SetLtS.self,
Instructions.CmovIz.self,
Instructions.CmovNz.self,
Instructions.RotL64.self,
Expand Down Expand Up @@ -155,7 +166,6 @@ public class InstructionTable {
}

logger.debug("initializing \(instType)")
// TODO: log errors
return try? instType.init(data: data[relative: 1...])
}
}
12 changes: 6 additions & 6 deletions PolkaVM/Sources/PolkaVM/Instructions/BranchInstructionBase.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import TracingUtils

private let logger = Logger(label: "Branch Instruction")
private let logger = Logger(label: "Branch ")

protocol Branch: Instruction {
var offset: UInt32 { get }
Expand Down Expand Up @@ -35,14 +35,14 @@ protocol BranchInstructionBase<Compare>: Branch {

extension BranchInstructionBase {
public static func parse(data: Data) throws -> (Registers.Index, UInt64, UInt32) {
let register = try Registers.Index(ra: data.at(relative: 0))
let register = try Registers.Index(r1: data.at(relative: 0))
let (value, offset): (UInt64, UInt32) = try Instructions.decodeImmediate2(data, divideBy: 16)
return (register, value, offset)
}

public func condition(state: VMState) -> Bool {
let regVal: UInt64 = state.readRegister(register)
logger.trace("\(Compare.self) a(\(regVal)) b(\(value)) => \(Compare.compare(a: regVal, b: value))")
logger.trace("🔀 \(Compare.self) a(\(regVal)) b(\(value)) => \(Compare.compare(a: regVal, b: value))")
return Compare.compare(a: regVal, b: value)
}
}
Expand All @@ -59,14 +59,14 @@ protocol BranchInstructionBase2<Compare>: Branch {
extension BranchInstructionBase2 {
public static func parse(data: Data) throws -> (Registers.Index, Registers.Index, UInt32) {
let offset: UInt32 = try Instructions.decodeImmediate(data.at(relative: 1...))
let r1 = try Registers.Index(ra: data.at(relative: 0))
let r2 = try Registers.Index(rb: data.at(relative: 0))
let r1 = try Registers.Index(r1: data.at(relative: 0))
let r2 = try Registers.Index(r2: data.at(relative: 0))
return (r1, r2, offset)
}

public func condition(state: VMState) -> Bool {
let (r1Val, r2Val): (UInt64, UInt64) = (state.readRegister(r1), state.readRegister(r2))
logger.trace("\(Compare.self) a(\(r1Val)) b(\(r2Val)) => \(Compare.compare(a: r1Val, b: r2Val))")
logger.trace("🔀 \(Compare.self) a(\(r1Val)) b(\(r2Val)) => \(Compare.compare(a: r1Val, b: r2Val))")
return Compare.compare(a: r1Val, b: r2Val)
}
}
Loading
Loading