Coder Social home page Coder Social logo

aluvm / rust-aluvm Goto Github PK

View Code? Open in Web Editor NEW
58.0 58.0 22.0 1.2 MB

Rust implementation of AluVM (RISC functional machine)

Home Page: https://docs.rs/aluvm

License: Apache License 2.0

Rust 99.78% Shell 0.03% TeX 0.18%
blockchain edge-computing embedded-systems functional-programming instruction-set-architecture microcontrollers risc rust smart-contracts virtual-machine

rust-aluvm's People

Contributors

6293 avatar crisdut avatar cymqqqq avatar dr-orlovsky avatar fengjian avatar josediegorobles avatar monaka avatar ukolovaolga avatar vuittont60 avatar whfuyn avatar zoedberg avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-aluvm's Issues

When `Number`s are less than 128, `to_u1024_bytes` converts them to zero

@dr-orlovsky

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ops_on_numbers() {
        let num1 = Number::from(127);
        assert_eq!(false, num1.is_zero())
    }
}

results in:

thread 'data::arithm::tests::ops_on_numbers' panicked at 'assertion failed: `(left == right)`
  left: `false`,
 right: `true`', src/data/arithm.rs:513:9

because of this:
https://github.com/internet2-org/rust-aluvm/blob/3b16ef83bad1b02137261739f9d22dfc1a966d6f/src/data/number.rs#L1066

It seems that 0 will be assigned to len when the number of bits is below 7, while 1 should be assigned.

`Number` often uses `to_u1024_bytes` for bitwise/arithmetic operations, but u1024 has 128bytes while `Number` is up to 1024bytes

impl BitAnd for Number {
type Output = Number;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
self.to_u1024_bytes().bitand(rhs.to_u1024_bytes()).into()
}
}

pub fn int_add(self, rhs: Self, flags: IntFlags) -> Option<Number> {
let layout = self.layout();
assert_eq!(layout, rhs.layout(), "adding numbers with different layout");
match (layout, flags.signed) {
(Layout::Integer(IntLayout { bytes, .. }), true) => self
.to_i1024_bytes()

Make put mnemonic consistent

Currently put mnemonic is used for both putting numbers and strings to registers. However, these two commands have different macro and display implementations: number format lists the literal first, while the string version puts the string literal as the last argument. This should be fixed.

Add information about AluVM-related projects to README

AluAsm (Alu assembler) makes it easier to use and debug AluVM (you can write assembly as files, not rust macros, and compile them + use libraries): https://github.com/pandoracore/aluasm

AluRE (Alu runtime environment) moves this further and provides runtime environment - but it is very early stage right now: https://github.com/pandoracore/AluRE

A concept of a high-level language for AluVM which may be used for smart contracts: https://github.com/rgb-org/contractum-lang

Simplify toolchain selection for lints

e.g. fmt check uses nightly while clippy is on stable. Since fmtand clippy yells at different points on stable and nightly, we would need to switch the compiler frequently on the local machine

Inconsistency in argument orgering

With the move to use Intel-style ordering in assembly ("destination-first ordering") we got into a quite inconsistent state:

  • not all mnemonics follow this rule, with a weird mix
  • ordering of the arguments in Enum code representation doesn't follow the rule
  • byte serialization (bytecode) differs from the rule.

We have the following options of introducing consistency here:

  • change everything to the new rule. This will break all binary compatibility and will require quite a lot of routine work to ensure nothing is missed
  • revert changes to mnemonic argument re-ordering and stick to the old "destination-last" ordering rule
  • leave mnemonics destination-first ordered - and the rest "destination-last" (i.e. make inconsistency systemic feature :)

I am pro second option, since a released RGB v0.10 already depends on the bytecode in AluVM, and if we use the first option, we need to fork AluVM and maintain two variants of it - one for RGB and the other one for the rest of the world.

Opinions? @6293

`CoreRegs::default()` causes stack overflow

Current Behavior

#[test]
fn my_test() { let _register = CoreRegs::default(); }

fails with

thread 'isa::exec::tests::my_test' has overflowed its stack
fatal runtime error: stack overflow

Cause

https://github.com/internet2-org/rust-aluvm/blob/a7e64abd4a7058bf9f06886452147810b4a5cf6d/src/reg/core_regs.rs#L99
With Box<[LibSite; CALL_STACK_SIZE]>, the value would be allocated to stack first, but CALL_STACK_SIZE = 1 << 16 is too big, resuting in overflow.

Possible Solutions

Use Vec<LibSite> instead.

Related Issues

rust-lang/rust#53827

Plan to move AluVM and related crates to different GitHub org

This github org (@Internet2-WG) was created to host projects related to better privacy and trustless decentralization in internet protocols.

AluVM and strict-encoding-related repos got to this organization since there seemed no place for them in other LNP/BP Standards Association github orgs at that time.

Now, we have a dedicated computing working group in LNP/BP Standards Association, called @Prometheus-WG. This WG seems to be a more native place for AluVM; I also plan to move all strict-encoding repositories there and repos from @pandoracore which are AluVM-related (assembly compiler, Alu runtime environment etc).

CC @zoedberg @cryptoquick @monaka @josediegorobles @6293 @UkolovaOlga - I plan to add you guys to the new org as team members; please let be know if you have arguments against the approach of migrating there. Otherwise I proceed with the moving at the end of the next week.

Introduce LibId

LibId must be deterministically computed from all library data

image

Use also library hash segment from #18

Failed tests by Secp256k1

My env is the same as #58.

Error log:

$ cargo test --no-fail-fast
   Compiling aluvm v0.6.0 (/home/monaka/rgb/rust-aluvm)
error[E0599]: no variant or associated item named `Secp256k1` found for enum `Instr` in the current scope
  --> examples/asm.rs:25:16
   |
25 |       let code = aluasm! {
   |  ________________^
26 | |         clr     r1024[5]                        ;
27 | |         put     5,a16[8]                        ;
28 | |         putif   0xaf67937b5498dc,r256[1]        ;
...  |
92 | |         ret                                     ;
93 | |     };
   | |_____^ variant or associated item not found in `Instr<_>`
   |
   = note: this error originates in the macro `instr` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0599`.
error: could not compile `aluvm` due to 4 previous errors

Is this issue related to #14 ?

Cursor doesn't read accross bytes

BitwiseOp::Shl(a2, shift, reg, idx) => {
writer.write_u1(u1::with(0b0))?;
writer.write_u1(a2)?;
writer.write_u5(shift)?;
writer.write_u4(reg)?;
writer.write_u5(idx)?;

Here, reg spans across 2 bytes (last bit of first byte to third bit of second byte). write_u4, however, does not handle such cases

fn extract(&mut self, bit_count: u3) -> Result<u8, CodeEofError> {

fix `neg` for `Number`

#[test]
    fn test_neg() {
        let x = Number::from(1i8);
        let y = Number::from(-1i8);
        assert_eq!(x.neg(), y);
    }

fails with

left: `Number { layout: Integer(IntLayout { signed: true, bytes: 1 }), bytes: "81" }`,
right: `Number { layout: Integer(IntLayout { signed: true, bytes: 1 }), bytes: "ff" }`'

Also, when the Number is unsigned, we could:

  • panic
  • accordingly change the IntLayout to signed (if it would cause overflow, change the bytes in the layout too)
  • accordingly change the IntLayout to signed (if it caused overflow, panic)

@dr-orlovsky wdyt? have a happy new year

`sub`/`dec` instruction fails

@dr-orlovsky

let code = aluasm! {
        put 4,a16[8];
        sub 9,a16[8];
        ret;
    };

this would fail because

https://github.com/internet2-org/rust-aluvm/blob/d67e2f558cf7c300dbd516897e81e5b13a82b609/src/isa/exec.rs#L471

here, val is stored as unsigned Number while Number::from(-step.as_i16()) produces signed Number, causing

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Integer(IntLayout { signed: false, bytes: 2 })`,
 right: `Integer(IntLayout { signed: true, bytes: 2 })`: subtracting numbers with different layout', src/data/arithm.rs:143:9

We can fix this to something like below?

if step.as_i16() < 0 {
  val.int_sub(Number::from(<convert -step to u16>), IntFlags {
     signed: false,
     wrap: true,
  })
}

`example/asm` may be broken.

Reproduction step:

cargo test --all-features
target/debug/examples/asm

Result:

thread 'main' panicked at 'invalid number literal `2.13`: Int(ParseIntError { kind: InvalidDigit })', examples/asm.rs:25:16
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Env:

cargo version
cargo 1.61.0 (a028ae4 2022-04-29)

Failed `cargo test` by unused imports

My env is:

$ cargo --version
cargo 1.61.0 (a028ae4 2022-04-29)
$ rustc --version
rustc 1.61.0 (fe5b13d68 2022-05-18)

The log is here:

$ cargo test
{snip}
  Compiling aluvm v0.6.0 (/home/monaka/rgb/rust-aluvm)
error: unused imports: `Reg8`, `RegBlockAR`
    --> src/isa/exec.rs:1019:29
     |
1019 |     use crate::reg::{Reg16, Reg8, RegBlockAR};
     |                             ^^^^  ^^^^^^^^^^
     |
note: the lint level is defined here
    --> src/lib.rs:13:34
     |
13   | #![deny(dead_code, missing_docs, warnings)]
     |                                  ^^^^^^^^
     = note: `#[deny(unused_imports)]` implied by `#[deny(warnings)]`

error: could not compile `aluvm` due to previous error
warning: build failed, waiting for other jobs to finish...

Assignment to large R-reg panics

Assignment to large R-regs like

regs.r2048[0] = Some([0u8; 256])

panics with uncanny message thread panicked while panicking. aborting.. This is a same bug as #40,

pub(crate) r1024: Box<[Option<[u8; 128]>; 32]>,
pub(crate) r2048: Box<[Option<[u8; 256]>; 32]>,
pub(crate) r4096: Box<[Option<[u8; 512]>; 32]>,
pub(crate) r8192: Box<[Option<[u8; 1024]>; 32]>,

too many things are on stack. R-regs should be something like

pub(crate) r1024: Confined<Vec<Option<[u8; 128]>>, 32, 32>,
pub(crate) r2048: Confined<Vec<Option<[u8; 256]>>, 32, 32>,
pub(crate) r4096: Confined<Vec<Option<[u8; 512]>>, 32, 32>,
pub(crate) r8192: Confined<Vec<Option<[u8; 1024]>>, 32, 32>,

false overflow on `int_add`

Current Behavior

Number::from(-1).int_add(Number::from(-2), IntFlags { signed: true, wrap: false })

returns None, despite the fact that it is not overflowing.

Cause

https://github.com/internet2-org/rust-aluvm/blob/fc00a25e1dd55824bd89716e28be297a5945c0ab/src/data/arithm.rs#L120

Here, we calculate the addition by converting Numbers to u1024. u1024, however, is not capable of judging negative overflow (of course because u1024 is "unsigned")

More specifically, u1024 will assert overflow whenever a carry bit results in > 0. But in an addition of two negative numbers, -1 and -2 for example, the carry bit hits 1 and we should ignore that.

Possible Solutions

  • implement big signed int (i256, i512, i1024) in rust-amplify
    • this would look like:
pub fn int_add(self, rhs: Self, flags: IntFlags) -> Option<Number> {
        let layout = self.layout();
        assert_eq!(layout, rhs.layout(), "adding numbers with different layout");
        match layout {
            // Signed and unsigned integers do not differ in their addition, since we use
            // two's complement system
            Layout::Integer(IntLayout { .. }) => {
                
                let (res, mut overflow) = {
                    match flags.signed {
                        true => {
                            let val1 = self.to_i1024_bytes();
                            let val2 = rhs.to_i1024_bytes();
                            val1.overflowing_add(val2);
                        },
                        false => {
                            let val1 = self.to_u1024_bytes();
                            let val2 = rhs.to_u1024_bytes();
                            val1.overflowing_add(val2);
                        }
                }
                let mut res = Number::from(res);
                overflow |= !res.reshape(layout);
                if !overflow || flags.wrap {
                    Some(res)
                } else {
                    None
                }
            }
            Layout::Float(_) => panic!("integer addition of float numbers"),
        }
    }
  • do not implement big signed int and just implement the algorithm directly
    • this sample is based on the fact that in integer addition A + B = C, C is overflowing if and only if MSB(A) == MSB(B) and MSB(A) != MSB(C)
pub fn int_add(self, rhs: Self, flags: IntFlags) -> Option<Number> {
        let layout = self.layout();
        assert_eq!(layout, rhs.layout(), "adding numbers with different layout");
        match layout {
            Layout::Integer(IntLayout { .. }) => {
                let mut ret = Number::zero(Layout::Integer(IntLayout {
                    signed: flags.signed,
                    bytes: layout.bytes(),
                }));
                let mut carry = 0u8;
                for i in 0..layout.bytes() {
                    let (res, flag) = self[i].overflowing_add(carry);
                    carry = flag as u8;
                    let (res, flag) = res.overflowing_add(rhs[i]);
                    carry += flag as u8;
                    ret[i] = res;
                }
                let overflow = {
                    if flags.signed {
                        let sign_byte = layout.sign_byte();
                        let is_self_positive = self[sign_byte] & 0x80 == 0;
                        let is_rhs_positive = rhs[sign_byte] & 0x80 == 0;
                        let is_ret_positive = ret[sign_byte] & 0x80 == 0;
                        (is_self_positive == is_rhs_positive) && (is_rhs_positive ^ is_ret_positive)
                    } else {
                        carry > 0
                    }
                };
                if !overflow || flags.wrap {
                    Some(ret)
                } else {
                    None
                }
            }
            Layout::Float(_) => panic!("integer addition of float numbers"),
        }
    }

Improve float to `Number` conversions

We have to filter NaN and negative zero values for float numbers and convert them into deterministic representation of MaybeNumber::None and positive zero

Can't pass `cargo build`.

I'll send a PR soon.

my environment.

$ cargo version
cargo 1.66.0 (d65d197ad 2022-11-15)
$ rustc --version
rustc 1.66.0 (69f9c33d7 2022-12-12)

error messages.

cargo check
    Checking aluvm v0.10.0-rc.1 (/home/monaka/diamondhands-dev/rust-aluvm)
error[E0433]: failed to resolve: use of undeclared crate or module `std`
  --> src/program.rs:28:5
   |
28 | use std::collections::btree_map;
   |     ^^^ use of undeclared crate or module `std`

error[E0433]: failed to resolve: could not find `std` in the list of imported crates
  --> src/library/lib.rs:49:22
   |
49 | #[derive(StrictType, StrictEncode, StrictDecode)]
   |                      ^^^^^^^^^^^^ could not find `std` in the list of imported crates
   |
   = note: this error originates in the derive macro `StrictEncode` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0433]: failed to resolve: could not find `std` in the list of imported crates
   --> src/library/lib.rs:311:22
    |
311 | #[derive(StrictType, StrictEncode, StrictDecode)]
    |                      ^^^^^^^^^^^^ could not find `std` in the list of imported crates
    |
    = note: this error originates in the derive macro `StrictEncode` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0433`.
error: could not compile `aluvm` due to 3 previous errors

expected `Result<Reg16, OverflowError>`, found `Result<Reg16, OverflowError<u8>>`

I was compiling a rgb dependencies inside my project but I have this error

   Compiling aluvm v0.10.6
   Compiling bp-consensus v0.10.11
error[E0308]: mismatched types
   --> /home/vincent/.cargo/registry/src/index.crates.io-6f17d22bba15001f/aluvm-0.10.6/src/reg/indexes.rs:425:9
    |
424 |     fn try_from(value: Reg32) -> Result<Self, Self::Error> {
    |                                  ------------------------- expected `Result<Reg16, OverflowError>` because of return type
425 |         u4::try_from(value as u8).map(Reg16::from)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Reg16, OverflowError>`, found `Result<Reg16, OverflowError<u8>>`
    |
    = note: expected enum `Result<_, OverflowError<usize>>`
               found enum `Result<_, OverflowError<u8>>`

error[E0308]: mismatched types
   --> /home/vincent/.cargo/registry/src/index.crates.io-6f17d22bba15001f/aluvm-0.10.6/src/reg/indexes.rs:528:9
    |
527 |     fn try_from(value: Reg32) -> Result<Self, Self::Error> {
    |                                  ------------------------- expected `Result<Reg8, OverflowError>` because of return type
528 |         u3::try_from(value as u8).map(Reg8::from)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Reg8, OverflowError>`, found `Result<Reg8, OverflowError<u8>>`
    |
    = note: expected enum `Result<_, OverflowError<usize>>`
               found enum `Result<_, OverflowError<u8>>`

error[E0308]: mismatched types
   --> /home/vincent/.cargo/registry/src/index.crates.io-6f17d22bba15001f/aluvm-0.10.6/src/reg/indexes.rs:620:9
    |
619 |     fn try_from(value: Reg32) -> Result<Self, Self::Error> {
    |                                  ------------------------- expected `Result<RegS, OverflowError>` because of return type
620 |         u5::try_from(value as u8).map(RegS::from)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<RegS, OverflowError>`, found `Result<RegS, OverflowError<u8>>`
    |
    = note: expected enum `Result<_, OverflowError<usize>>`
               found enum `Result<_, OverflowError<u8>>`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `aluvm` (lib) due to 3 previous errors
warning: build failed, waiting for other jobs to finish..

Not sure why :/

the dependencies that I am using

# RGB and related
amplify = "=4.5.0"
base64 = "0.13.0"
bp-core = "=0.10.11"
commit_verify = "=0.10.6"
futures = "0.3"
hex = "0.4"
reqwest = { version = "0.11", default-features = false, features = ["json", "blocking"] }
rgb-contracts = { version = "=0.10.2", features = ["electrum"] }
rgb_core = { package = "rgb-core", version = "=0.10.8" }
rgb-lib = { git = "https://github.com/RGB-Tools/rgb-lib", branch = "rln_v0.10" }
rgb-std = "=0.10.9"
rgb-wallet = "=0.10.9"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
strict_encoding = "=2.6.1"
tokio = { version = "1.36", features = ["macros", "rt-multi-thread"] }

Suppress AluVM trace eprints

The output from several eprint and eprintln instructions appears on the console while calling aluvm methods.

This is inconvenient and I think this output should be suppressed.

I propose to protect those eprint's behind a feature flag (e.g. log).

Comparing `Number`s results in infinite loop

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cmp_numbers() {
        let num0 = Number::from(1);
        let num1 = Number::from(2);
        assert_eq!(num0, num1);
    }
}

results in

thread 'data::arithm::tests::cmp_numbers' has overflowed its stack
fatal runtime error: stack overflow

because eq method calls itself.
https://github.com/internet2-org/rust-aluvm/blob/3b16ef83bad1b02137261739f9d22dfc1a966d6f/src/data/arithm.rs#L28

Maybe we can compare two Numbers by converting them to corresponding integer/float types, just like cmp method does?

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.