|
1 | 1 | package host_call
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
| 5 | + "errors" |
| 6 | + "log" |
4 | 7 | "math"
|
5 | 8 |
|
6 | 9 | "github.com/eigerco/strawberry/internal/block"
|
7 | 10 | "github.com/eigerco/strawberry/internal/common"
|
8 | 11 | "github.com/eigerco/strawberry/internal/crypto"
|
9 | 12 | "github.com/eigerco/strawberry/internal/jamtime"
|
10 | 13 | . "github.com/eigerco/strawberry/internal/polkavm"
|
| 14 | + "github.com/eigerco/strawberry/internal/polkavm/interpreter" |
11 | 15 | "github.com/eigerco/strawberry/internal/service"
|
12 | 16 | "github.com/eigerco/strawberry/internal/work"
|
| 17 | + "github.com/eigerco/strawberry/pkg/serialization/codec/jam" |
13 | 18 | )
|
14 | 19 |
|
15 | 20 | // HistoricalLookup ΩH(ϱ, ω, µ, (m, e), s, d, t)
|
@@ -366,7 +371,91 @@ func Invoke(
|
366 | 371 | mem Memory,
|
367 | 372 | ctxPair RefineContextPair,
|
368 | 373 | ) (Gas, Registers, Memory, RefineContextPair, error) {
|
369 |
| - return gas, regs, mem, ctxPair, nil |
| 374 | + if gas < InvokeCost { |
| 375 | + return gas, regs, mem, ctxPair, ErrOutOfGas |
| 376 | + } |
| 377 | + gas -= InvokeCost |
| 378 | + // let [n, o] = ω7,8 |
| 379 | + pvmKey, addr := regs[A0], regs[A1] |
| 380 | + |
| 381 | + // let (g, w) = (g, w) ∶ E8(g) ⌢ E#8(w) = μo⋅⋅⋅+112 if No⋅⋅⋅+112 ⊂ V∗μ |
| 382 | + invokeGas, err := readNumber[Gas](mem, uint32(addr), 8) |
| 383 | + if err != nil { |
| 384 | + return gas, withCode(regs, OOB), mem, ctxPair, nil |
| 385 | + } |
| 386 | + var invokeRegs Registers // w |
| 387 | + for i := range 13 { |
| 388 | + invokeReg, err := readNumber[uint64](mem, uint32(addr+(uint64(i+1)*8)), 8) |
| 389 | + if err != nil { |
| 390 | + return gas, withCode(regs, OOB), mem, ctxPair, nil |
| 391 | + } |
| 392 | + invokeRegs[i] = invokeReg |
| 393 | + } |
| 394 | + |
| 395 | + // let (c, i′, g′, w′, u′) = Ψ(m[n]p, m[n]i, g, w, m[n]u) |
| 396 | + pvm, ok := ctxPair.IntegratedPVMMap[pvmKey] |
| 397 | + if !ok { // if n ∉ m |
| 398 | + return gas, withCode(regs, WHO), mem, ctxPair, nil // (WHO, ω8, μ, m) |
| 399 | + } |
| 400 | + updateIntegratedPVM := func(isHostCall bool, resultInstr uint32, resultMem Memory) { |
| 401 | + pvm.Ram = resultMem |
| 402 | + if isHostCall { |
| 403 | + // m*[n]i = i′ + 1 if c ∈ {̵h} × NR |
| 404 | + pvm.InstructionCounter = resultInstr + 1 |
| 405 | + } else { |
| 406 | + // m*[n]i = i′ |
| 407 | + pvm.InstructionCounter = resultInstr |
| 408 | + } |
| 409 | + ctxPair.IntegratedPVMMap[pvmKey] = pvm |
| 410 | + } |
| 411 | + |
| 412 | + // we only parse the code and jump table as we are not expected to invoke a full program |
| 413 | + program := &Program{} |
| 414 | + if err := ParseCodeAndJumpTable(uint32(len(pvm.Code)), NewReader(bytes.NewReader(pvm.Code)), program); err != nil { |
| 415 | + return gas, withCode(regs, PANIC), mem, ctxPair, nil |
| 416 | + } |
| 417 | + |
| 418 | + log.Println("invokeGas", invokeGas) |
| 419 | + log.Println("invokeRegs", invokeRegs) |
| 420 | + resultInstr, resultGas, resultRegs, resultMem, hostCall, invokeErr := interpreter.Invoke(program, nil, pvm.InstructionCounter, invokeGas, invokeRegs, pvm.Ram) |
| 421 | + |
| 422 | + if bb, err := jam.Marshal([14]uint64(append([]uint64{uint64(resultGas)}, resultRegs[:]...))); err != nil { |
| 423 | + return gas, withCode(regs, OOB), mem, ctxPair, nil // (OOB, ω8, μ, m) |
| 424 | + } else if err := mem.Write(uint32(addr), bb); err != nil { |
| 425 | + return gas, withCode(regs, OOB), mem, ctxPair, nil // (OOB, ω8, μ, m) |
| 426 | + } |
| 427 | + if invokeErr != nil { |
| 428 | + if errors.Is(invokeErr, ErrOutOfGas) { |
| 429 | + updateIntegratedPVM(false, resultInstr, resultMem) |
| 430 | + return gas, withCode(regs, OOG), mem, ctxPair, nil // (OOG, ω8, μ*, m*) |
| 431 | + } |
| 432 | + if errors.Is(invokeErr, ErrHalt) { |
| 433 | + updateIntegratedPVM(false, resultInstr, resultMem) |
| 434 | + return gas, withCode(regs, HALT), mem, ctxPair, nil // (HALT, ω8, μ*, m*) |
| 435 | + } |
| 436 | + if errors.Is(invokeErr, ErrHostCall) { |
| 437 | + updateIntegratedPVM(true, resultInstr, resultMem) |
| 438 | + regs[A1] = uint64(hostCall) |
| 439 | + return gas, withCode(regs, HOST), mem, ctxPair, nil // (HOST, h, μ*, m*) |
| 440 | + } |
| 441 | + pageFault := &ErrPageFault{} |
| 442 | + if errors.As(invokeErr, &pageFault) { |
| 443 | + updateIntegratedPVM(false, resultInstr, resultMem) |
| 444 | + regs[A1] = uint64(pageFault.Address) |
| 445 | + return gas, withCode(regs, FAULT), mem, ctxPair, nil |
| 446 | + } |
| 447 | + panicErr := &ErrPanic{} |
| 448 | + if errors.As(invokeErr, &panicErr) { |
| 449 | + updateIntegratedPVM(false, resultInstr, resultMem) |
| 450 | + return gas, withCode(regs, PANIC), mem, ctxPair, nil |
| 451 | + } |
| 452 | + |
| 453 | + // must never occur |
| 454 | + panic(invokeErr) |
| 455 | + } |
| 456 | + |
| 457 | + updateIntegratedPVM(false, resultInstr, resultMem) |
| 458 | + return gas, withCode(regs, HALT), mem, ctxPair, nil // (HALT, ω8, μ*, m*) |
370 | 459 | }
|
371 | 460 |
|
372 | 461 | // Expunge ΩX(ϱ, ω, µ, (m, e))
|
|
0 commit comments