FuelLabs / fuel-specs

📝 Specifications for the Fuel protocol and the FuelVM, a blazingly fast blockchain VM.
https://fuellabs.github.io/fuel-specs/master
Apache License 2.0
1.78k stars 711 forks source link

SYSCALL opcode #521

Closed SilentCicero closed 1 year ago

SilentCicero commented 1 year ago

Abstract

We have been speaking with several projects that would like to extend some of the FuelVM capabilities.

While extensibility has not been a priority of the VM and tooling at the moment, I believe many cases of extensibility could be covered by having a SYSCALL opcode that is integrated into our tooling and VM which can be easily extended by third-party developers.

Most modern VM and ISA specifications usually provide a system call for a variety of purposes, I don't see the FuelVM being any different.

Roadmap Considerations

The SYSCALL opcode would be a no-op for our planned current roadmap deployments. But would be available for anyone to fill or extend on their own if they had a need.

Tooling Advantages:

This would allow people to easily extend the VM and access the extensions via Sway and the tooling without having to dramatically alter our stack and tooling (i.e. republish fuel-vm binaries etc).

This addition could foster a new kind of plugin system for the FuelVM, with minimal changes to our existing stack.

Register Architecture

For this I see two approaches, a minimal use of a single register with the rest being left unused or the first register used to flag the system operation, and the last two for the start and length of memory for writes.

Regardless, I'm open to ideas as to how we would want to specify that.

Use for Debugging

This opcode could also be used for debugging purposes.

Prior Art:

MIPS: https://www.doc.ic.ac.uk/lab/secondyear/spim/node8.html RiscV: https://github.com/protolambda/asterisc/blob/master/rvgo/fast/vm.go#L347

Dentosal commented 1 year ago

I agree that risc-v ecall is a nice model for opcodes like this. Since we have four register slots available per opcode, I'd suggest we use them all. The form should likely be just ECAL $rA $rB $rC $rD where all four registers are passed to the external system. After the system is done with processing them, the result is written in the first two. We can have a convention where $rA holds operation, but some systems might want to use all of the values differently, and there's not much need to enforce the convention on a technical level. Two return values are useful for performance and typing reasons, since we could use one of them to return return code and the other for return value. This also allows full 64bit return values.

On a technical level (in FuelVM) there are multiple ways to implement this. How does the external system integrate into the VM? Maybe it's just a callback function that you register when initializing it. Since we're starting just as a no-op, we can figure this out later. We'll simply reserve the opcode and make it do nothing for now. One concern is the gas costing of this operation, but maybe the external system also provides a callback for that as well.

SilentCicero commented 1 year ago

@Dentosal do you mind making a proposal PR for how you see this opcode working, agreed with the above considerations.

I think this format makes sense: ECAL $rA $rB $rC $rD

How does the external system integrate into the VM?

My thinking would be that either a developer could fork the fuel-vm and make the necessary modifications, we would provide a hello world example. This way they could fully modify what they need easily, then just write the Sway library necessary to tap into it.

They might have to do a rebuild of the client with the new fuel-vm, but at least tapping into and running everything else remains the same. Yes, for now it's all a no-op and placeholder. We could simply do a hello world console log example for now.

Curious to hear from @Voxelot as well.

Dentosal commented 1 year ago

Here's the spec PR: https://github.com/FuelLabs/fuel-specs/pull/523. I've scheduled this Friday for the VM-side implementation.