Coder Social home page Coder Social logo

fuel-asm's Introduction

โš  Archival Notice

This repo is no longer active and has been moved to: https://github.com/FuelLabs/fuel-vm/tree/master/fuel-asm

Fuel ASM

build crates.io docs discord

Instruction set for the FuelVM.

Compile features

  • std: Unless set, the crate will link to the core-crate instead of the std-crate. More info here.
  • serde: Add support for serde for the types exposed by this crate.

Example

use fuel_asm::*;
use Opcode::*;

// A sample program to perform ecrecover
let program = vec![
    MOVE(0x10, 0x01),      // set r[0x10] := $one
    SLLI(0x20, 0x10, 5),   // set r[0x20] := `r[0x10] << 5 == 32`
    SLLI(0x21, 0x10, 6),   // set r[0x21] := `r[0x10] << 6 == 64`
    ALOC(0x21),            // alloc `r[0x21] == 64` to the heap
    ADDI(0x10, 0x07, 1),   // set r[0x10] := `$hp + 1` (allocated heap)
    MOVE(0x11, 0x04),      // set r[0x11] := $ssp
    ADD(0x12, 0x04, 0x20), // set r[0x12] := `$ssp + r[0x20]`
    ECR(0x10, 0x11, 0x12), // recover public key in memory[r[0x10], 64]
    RET(0x01),             // return `1`
];

// Convert program to bytes representation
let bytes: Vec<u8> = program.iter().copied().collect();

// A program can be reconstructed from an iterator of bytes
let restored = Opcode::from_bytes_iter(bytes.iter().copied());

assert_eq!(program, restored);

// Every instruction can be described as `u32` big-endian bytes
let halfwords: Vec<u32> = program.iter().copied().map(u32::from).collect();
let bytes = halfwords.iter().copied().map(u32::to_be_bytes).flatten();
let restored = Opcode::from_bytes_iter(bytes);

assert_eq!(program, restored);

// We can also reconstruct the instructions individually
let restored: Vec<Opcode> = halfwords.iter().copied().map(Opcode::from).collect();

assert_eq!(program, restored);

// We have an unchecked variant for optimal performance
let restored: Vec<Opcode> = halfwords
    .iter()
    .copied()
    .map(|w| unsafe { Opcode::from_bytes_unchecked(&w.to_be_bytes()) })
    .collect();

assert_eq!(program, restored);

// Finally, we have [`Instruction`] to allow optimal runtime parsing of the components of the
// opcode
//
// `Opcode` itself is only but an abstraction/helper to facilitate visualization, but the VM is
// expected to use raw instructions
let instrs: Vec<Instruction> = program.iter().copied().map(Instruction::from).collect();
let restored: Vec<Opcode> = instrs.iter().copied().map(Opcode::from).collect();

assert_eq!(program, restored);

// An instruction is composed by the opcode representation registers Id and immediate values
assert_eq!(instrs[1].op(), OpcodeRepr::SLLI as u8);
assert_eq!(instrs[1].ra(), 0x20);
assert_eq!(instrs[1].rb(), 0x10);
assert_eq!(instrs[1].imm12(), 5);

fuel-asm's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fuel-asm's Issues

Add `MCPI` Opcode

Implement https://github.com/FuelLabs/fuel-specs/blob/master/specs/vm/opcodes.md#mcpi-memory-copy-immediate

Steps

  1. Include an opcode identifier (from and to u8) in https://github.com/FuelLabs/fuel-asm/blob/master/src/opcode/consts.rs
  2. Add the opcode variant with the documentation in https://github.com/FuelLabs/fuel-asm/blob/master/src/opcode.rs
    1. The constant representation defined in the previous step must be implemented in https://github.com/FuelLabs/fuel-asm/blob/master/src/opcode.rs#L1265
    2. The references to ra and rb must be defined in https://github.com/FuelLabs/fuel-asm/blob/master/src/opcode.rs#L1369
    3. The opcode into half word implementation must be added in https://github.com/FuelLabs/fuel-asm/blob/master/src/opcode.rs#L1492
  3. Add the new opcode to the test cases for encode/decode: https://github.com/FuelLabs/fuel-asm/blob/master/tests/encoding.rs#L11

InstructionResult doesn't follow idiomatic Rust conventions for Result types

InstructionResult includes the following fields:

/// Describe a panic reason with the instruction that generated it
pub struct InstructionResult {
    reason: PanicReason,
    instruction: Instruction,
}

This is not a very user-friendly type because a successful script result is shown like this to users of the Rust types:

ScriptResult {
	result: InstructionResult {
		reason: RESERV00,
		instruction: Instruction {
			op: 0,
			ra: 0,
			rb: 0,
			rc: 0,
			rd: 0,
			imm06: 0,
			imm12: 0,
			imm18: 0,
			imm24: 0
		}
	},
	gas_used: 22
}

The problem with this representation is that it's not immediately obvious to users that this means the script succeeded. While the encoded form of this instruction result as a word does match the specs (0), users logging and debugging their transactions will just see RESERV00 in the final receipt of their transaction and have to know what that means. Rather than using dummy default instructions and non-existent panic reasons to indicate success, we should consider using an enum similar to the result type in Rust.

This could look something like this:

pub enum InstructionResult {
    Success(Instruction),
    Panic {
        reason: PanicReason,
        instruction: Instruction
    }
}

If InstructionResult::Success.into() == 0u64, this would match the specs and drastically improve clarity to users of the Rust types.

Create constants for flag opcodes

We should have API abstractions for the internal VM flags so the user will not have to use magic numbers to manipulate the execution flags.

The current use cases are:

Opcode::FLAG($r == 0x01) for unsafe math:
https://github.com/FuelLabs/fuel-vm/blob/72ee94908ef2400b41966e927124b05c924a7c4b/src/interpreter.rs#L84-L87

Opcode::FLAG($r == 0x02) for wrapping arithmetic:
https://github.com/FuelLabs/fuel-vm/blob/72ee94908ef2400b41966e927124b05c924a7c4b/src/interpreter.rs#L90-L93

Parse `Word` into 2x opcode internals

In the VM, every opcode is executed in pairs encoded into a Word.

Currently, we parse the opcodes individually from halfwords and perform match pattern more than once. As performance improvement, we need a mechanism to use a single parse instruction that will, from a Word, output its internals without unnecessary overhead such as branching.

We should achieve something similar to fn(Word) -> ((u8, RegisterId, RegisterId, RegisterId, RegisterId, Immediate06, Immediate12, Immediate18, Immediate24), (u8, RegisterId, RegisterId, RegisterId, RegisterId, Immediate06, Immediate12, Immediate18, Immediate24)) being every of these tuples the required data to fully represent an instruction.

However, having such big tuples is clearly anti-pattern, so we need a new structure that will represent them. The VM runtime will use this new instruction instead of the Opcode. However, Opcode will remain available so other libraries can benefit from its abstraction.

Solution

  1. Create a new structure to encapsulate a parsed instruction. Use From u32 as reference
    1. u8 - Instruction representation. Check OpcodeRepr. A byte is more than enough to represent all instruction variants.
    2. RegisterId - $rA
    3. RegisterId - $rB
    4. RegisterId - $rC
    5. RegisterId - $rD
    6. Immediate06
    7. Immediate12
    8. Immediate18
    9. Immediate24
  2. Create an associated function of Opcode that will fn(Word) -> (x, x), where x is the struct declared in 1
  3. Refactor From Opcode for u32 to internally use x instead of repeating the bitmask pattern
  4. Export x in the library root/prelude
  5. If applicable, propose intrinsic optimizations
  6. Update the encode tests to map from/to x/Opcode

Shield `unsafe` behind `optimized` feature

Implement a new feature optimized to shield all unsafe usage.

When this feature is on, unsafe is allowed

When this feature is off, we should introduce forbid_unsafe in the root of the library:
src/lib.rs: #![cfg_attr(not(feature = "optimized"), forbid(unsafe_code))]

This means that all functions that use unsafe will have to be reimplemented with their safer (and potentially slower) counterparts

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.