diff --git a/Cargo.lock b/Cargo.lock index 274138f0..7276536c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,8 +5,7 @@ version = 3 [[package]] name = "aluvm" version = "0.11.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10be187b383247e1902aa5a415f76ffc9a04f197829c46b9ccb6da3582e394f" +source = "git+https://github.com/AluVM/rust-aluvm?branch=master#3e9bcfbc00b72dbc23a0538230a452bb338190d1" dependencies = [ "amplify", "baid58", diff --git a/Cargo.toml b/Cargo.toml index 158a3d67..0c2900c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,3 +59,7 @@ wasm-bindgen-test = "0.3" [package.metadata.docs.rs] features = [ "all" ] + +[patch.crates-io] +# TODO: Remove after new release +aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "master" } diff --git a/src/vm/macroasm.rs b/src/vm/macroasm.rs index cf996f46..2e9b3406 100644 --- a/src/vm/macroasm.rs +++ b/src/vm/macroasm.rs @@ -23,6 +23,7 @@ #[macro_export] macro_rules! rgbasm { ($( $tt:tt )+) => {{ #[allow(unused_imports)] { + use $crate::AssignmentType; use $crate::vm::{RgbIsa, ContractOp, TimechainOp}; use $crate::vm::aluasm_isa; use $crate::isa_instr; @@ -34,8 +35,28 @@ macro_rules! rgbasm { macro_rules! isa_instr { (pcvs $no:literal) => {{ RgbIsa::Contract(ContractOp::PcVs($no.into())) }}; (pccs $no1:literal, $no2:literal) => {{ RgbIsa::Contract(ContractOp::PcCs($no1.into(), $no2.into())) }}; - (ldg $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdG($t.into(), $no, RegS::from($s_idx))) }}; - (lds $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdS($t.into(), $no, RegS::from($s_idx))) }}; - (ldp $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdP($t.into(), $no, RegS::from($s_idx))) }}; + (cng $t:literal,a8[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnG($t.into(), Reg32::from($a_idx))) }}; + (cnc $t:literal,a16[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnC($t.into(), Reg32::from($a_idx))) }}; + (ldg $t:literal,a8[$a_idx:literal],s16[$s_idx:literal]) => {{ + RgbIsa::Contract(ContractOp::LdG( + GlobalStateType::from($t as u16), + Reg32::from($a_idx), + RegS::from($s_idx), + )) + }}; + (ldp $t:literal,a16[$a_idx:literal],s16[$s_idx:literal]) => {{ + RgbIsa::Contract(ContractOp::LdS( + AssignmentType::from($t as u16), + Reg32::from($a_idx), + RegS::from($s_idx), + )) + }}; + (lds $t:literal,a16[$a_idx:literal],s16[$s_idx:literal]) => {{ + RgbIsa::Contract(ContractOp::LdS( + AssignmentType::from($t as u16), + Reg32::from($a_idx), + RegS::from($s_idx), + )) + }}; ($op:ident $($tt:tt)+) => {{ compile_error!(concat!("unknown RGB assembly opcode `", stringify!($op), "`")) }}; } diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs index b8676913..fe575152 100644 --- a/src/vm/op_contract.rs +++ b/src/vm/op_contract.rs @@ -59,29 +59,39 @@ pub enum ContractOp { /// Counts number of global state items of the provided type in the contract /// state and puts the number to the destination `a16` register. #[display("cnc {0},a16{1}")] - CnC(AssignmentType, Reg32), + CnC(GlobalStateType, Reg32), - /// Loads input (previous) state with type id from the first argument and + /// Loads global state from the current operation with type id from the + /// first argument and index from the second argument into a + /// register provided in the third argument. + /// + /// If the state is absent sets `st0` to `false` and terminates the program. + #[display("ldg {0},{1},{2}")] + LdG(GlobalStateType, Reg32, RegS), + + /// Loads owned structured state with type id from the first argument and /// index from the second argument into a register provided in the third /// argument. /// - /// If the state is absent or is not a structured state sets `st0` to - /// `false` and terminates the program. + /// If the state is absent, the register containing index is not set or + /// is not a structured state sets `st0` to `false` and terminates the + /// program. /// /// If the state at the index is concealed, sets destination to `None`. - #[display("ldp {0},{1},{2}")] - LdP(AssignmentType, u16, RegS), + #[display("lds {0},{1},{2}")] + LdS(AssignmentType, Reg32, RegS), - /// Loads owned structured state with type id from the first argument and + /// Loads input (previous) state with type id from the first argument and /// index from the second argument into a register provided in the third /// argument. /// - /// If the state is absent or is not a structured state sets `st0` to - /// `false` and terminates the program. + /// If the state is absent, the register containing index is not set or + /// is not a structured state sets `st0` to `false` and terminates the + /// program. /// /// If the state at the index is concealed, sets destination to `None`. - #[display("lds {0},{1},{2}")] - LdS(AssignmentType, u16, RegS), + #[display("ldp {0},{1},{2}")] + LdP(AssignmentType, Reg32, RegS), /// Loads owned fungible state with type id from the first argument and /// index from the second argument into `a64` register provided in the third @@ -94,14 +104,6 @@ pub enum ContractOp { #[display("ldf {0},{1},a64{2}")] LdF(AssignmentType, u16, Reg32), - /// Loads global state from the current operation with type id from the - /// first argument and index from the second argument into a register - /// provided in the third argument. - /// - /// If the state is absent sets `st0` to `false` and terminates the program. - #[display("ldg {0},{1},{2}")] - LdG(GlobalStateType, u8, RegS), - /// Loads part of the contract global state with type id from the first /// argument at the depth from the second argument into a register /// provided in the third argument. @@ -109,7 +111,7 @@ pub enum ContractOp { /// If the state is absent or concealed sets destination to `None`. /// Does not modify content of `st0` register. #[display("ldc {0},{1},{2}")] - LdC(GlobalStateType, u16, RegS), + LdC(GlobalStateType, Reg32, RegS), /// Loads operation metadata into a register provided in the third argument. /// @@ -161,18 +163,19 @@ impl InstructionSet for ContractOp { fn dst_regs(&self) -> HashSet { match self { - ContractOp::CnP(_, reg) | - ContractOp::CnS(_, reg) | - ContractOp::CnG(_, reg) | - ContractOp::CnC(_, reg) => { + ContractOp::CnP(_, reg) | ContractOp::CnS(_, reg) | ContractOp::CnC(_, reg) => { set![Reg::A(RegA::A16, *reg)] } + ContractOp::CnG(_, reg) => { + set![Reg::A(RegA::A8, *reg)] + } ContractOp::LdF(_, _, reg) => { set![Reg::A(RegA::A64, *reg)] } - ContractOp::LdP(_, _, reg) | - ContractOp::LdS(_, _, reg) | + ContractOp::LdG(_, _, reg) | + ContractOp::LdS(_, _, reg) | + ContractOp::LdP(_, _, reg) | ContractOp::LdC(_, _, reg) | ContractOp::LdM(reg) => { set![Reg::S(*reg)] @@ -246,28 +249,37 @@ impl InstructionSet for ContractOp { ); } ContractOp::CnG(state_type, reg) => { - regs.set_n(RegA::A16, *reg, context.global.get(state_type).map(|a| a.len_u16())); + regs.set_n(RegA::A8, *reg, context.global.get(state_type).map(|a| a.len_u16())); } - ContractOp::CnC(_state_type, _reg) => { - // TODO: implement global contract state - fail!() + ContractOp::CnC(state_type, reg) => { + regs.set_n(RegA::A16, *reg, context.global.get(state_type).map(|a| a.len_u16())); } - ContractOp::LdP(state_type, index, reg) => { + ContractOp::LdP(state_type, reg_32, reg) => { + let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { + fail!() + }; + let index: u16 = reg_32.into(); + let Some(Ok(state)) = context .prev_state .get(state_type) - .map(|a| a.as_structured_state_at(*index)) + .map(|a| a.as_structured_state_at(index)) else { fail!() }; let state = state.map(|s| s.value.as_inner()); regs.set_s(*reg, state); } - ContractOp::LdS(state_type, index, reg) => { + ContractOp::LdS(state_type, reg_32, reg) => { + let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { + fail!() + }; + let index: u16 = reg_32.into(); + let Some(Ok(state)) = context .owned_state .get(*state_type) - .map(|a| a.into_structured_state_at(*index)) + .map(|a| a.into_structured_state_at(index)) else { fail!() }; @@ -284,19 +296,36 @@ impl InstructionSet for ContractOp { }; regs.set_n(RegA::A64, *reg, state.map(|s| s.value.as_u64())); } - ContractOp::LdG(state_type, index, reg) => { + ContractOp::LdG(state_type, reg_32, reg_s) => { + let Some(reg_32) = *regs.get_n(RegA::A8, *reg_32) else { + fail!() + }; + let index: u8 = reg_32.into(); + let Some(state) = context .global .get(state_type) - .and_then(|a| a.get(*index as usize)) + .and_then(|a| a.get(index as usize)) else { fail!() }; - regs.set_s(*reg, Some(state.value.as_inner())); + regs.set_s(*reg_s, Some(state.value.as_inner())); } - ContractOp::LdC(_state_type, _index, _reg) => { - // TODO: implement global contract state - fail!() + + ContractOp::LdC(state_type, reg_32, reg_s) => { + let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { + fail!() + }; + let index: u8 = reg_32.into(); + + let Some(state) = context + .global + .get(state_type) + .and_then(|a| a.get(index as usize)) + else { + fail!() + }; + regs.set_s(*reg_s, Some(state.value.as_inner())); } ContractOp::LdM(reg) => { regs.set_s(*reg, Some(context.metadata)); @@ -360,8 +389,8 @@ impl Bytecode for ContractOp { ContractOp::CnG(_, _) | ContractOp::CnC(_, _) => 4, - ContractOp::LdP(_, _, _) | ContractOp::LdS(_, _, _) | + ContractOp::LdP(_, _, _) | ContractOp::LdF(_, _, _) | ContractOp::LdC(_, _, _) => 6, ContractOp::LdG(_, _, _) => 5, @@ -383,10 +412,10 @@ impl Bytecode for ContractOp { ContractOp::CnG(_, _) => INSTR_CNG, ContractOp::CnC(_, _) => INSTR_CNC, - ContractOp::LdP(_, _, _) => INSTR_LDP, + ContractOp::LdG(_, _, _) => INSTR_LDG, ContractOp::LdS(_, _, _) => INSTR_LDS, + ContractOp::LdP(_, _, _) => INSTR_LDP, ContractOp::LdF(_, _, _) => INSTR_LDF, - ContractOp::LdG(_, _, _) => INSTR_LDG, ContractOp::LdC(_, _, _) => INSTR_LDC, ContractOp::LdM(_) => INSTR_LDM, @@ -420,17 +449,17 @@ impl Bytecode for ContractOp { writer.write_u5(reg)?; writer.write_u3(u3::ZERO)?; } - ContractOp::LdP(state_type, index, reg) => { + ContractOp::LdP(state_type, reg_32, reg_s) => { writer.write_u16(*state_type)?; - writer.write_u16(*index)?; - writer.write_u4(reg)?; - writer.write_u4(u4::ZERO)?; + writer.write_u5(reg_32)?; + writer.write_u8(reg_s)?; + writer.write_u3(u3::ZERO)?; } - ContractOp::LdS(state_type, index, reg) => { + ContractOp::LdS(state_type, reg_32, reg_s) => { writer.write_u16(*state_type)?; - writer.write_u16(*index)?; - writer.write_u4(reg)?; - writer.write_u4(u4::ZERO)?; + writer.write_u5(reg_32)?; + writer.write_u8(reg_s)?; + writer.write_u3(u3::ZERO)?; } ContractOp::LdF(state_type, index, reg) => { writer.write_u16(*state_type)?; @@ -438,17 +467,17 @@ impl Bytecode for ContractOp { writer.write_u5(reg)?; writer.write_u3(u3::ZERO)?; } - ContractOp::LdG(state_type, index, reg) => { + ContractOp::LdG(state_type, reg_a, reg_s) => { writer.write_u16(*state_type)?; - writer.write_u8(*index)?; - writer.write_u4(reg)?; - writer.write_u4(u4::ZERO)?; + writer.write_u5(*reg_a)?; + writer.write_u8(*reg_s)?; + writer.write_u3(u3::ZERO)?; } - ContractOp::LdC(state_type, index, reg) => { + ContractOp::LdC(state_type, reg_a, reg_s) => { writer.write_u16(*state_type)?; - writer.write_u16(*index)?; - writer.write_u4(reg)?; - writer.write_u4(u4::ZERO)?; + writer.write_u5(*reg_a)?; + writer.write_u4(reg_s)?; + writer.write_u3(u3::ZERO)?; } ContractOp::LdM(reg) => { writer.write_u4(reg)?; @@ -474,41 +503,32 @@ impl Bytecode for ContractOp { Ok(match reader.read_u8()? { INSTR_CNP => { let i = Self::CnP(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_CNS => { let i = Self::CnS(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_CNG => { let i = Self::CnG(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_CNC => { let i = Self::CnC(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_LDP => { let i = Self::LdP( reader.read_u16()?.into(), - reader.read_u16()?, - reader.read_u4()?.into(), - ); - reader.read_u4()?; // Discard garbage bits - i - } - INSTR_LDS => { - let i = Self::LdS( - reader.read_u16()?.into(), - reader.read_u16()?, - reader.read_u4()?.into(), + reader.read_u5()?.into(), + reader.read_u8()?.into(), ); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_LDF => { @@ -523,19 +543,28 @@ impl Bytecode for ContractOp { INSTR_LDG => { let i = Self::LdG( reader.read_u16()?.into(), - reader.read_u8()?, - reader.read_u4()?.into(), + reader.read_u5()?.into(), + reader.read_u8()?.into(), ); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits + i + } + INSTR_LDS => { + let i = Self::LdS( + reader.read_u16()?.into(), + reader.read_u5()?.into(), + reader.read_u8()?.into(), + ); + reader.read_u3()?; // Discard garbage bits i } INSTR_LDC => { let i = Self::LdC( reader.read_u16()?.into(), - reader.read_u16()?, - reader.read_u4()?.into(), + reader.read_u5()?.into(), + reader.read_u8()?.into(), ); - reader.read_u4()?; // Discard garbage bits + reader.read_u3()?; // Discard garbage bits i } INSTR_LDM => {