diff --git a/src/vm/isa.rs b/src/vm/isa.rs index 63b80c5c..8cee1c97 100644 --- a/src/vm/isa.rs +++ b/src/vm/isa.rs @@ -28,13 +28,25 @@ use std::ops::RangeInclusive; use aluvm::isa; use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; use aluvm::library::{CodeEofError, LibSite, Read, Write}; -use aluvm::reg::CoreRegs; +use aluvm::reg::{CoreRegs, Reg16, RegS}; +use amplify::Wrapper; + +pub const INSTR_CNP: u8 = 0b11_000_000; +pub const INSTR_CNS: u8 = 0b11_000_001; +pub const INSTR_CNG: u8 = 0b11_000_010; +pub const INSTR_CNC: u8 = 0b11_000_011; +pub const INSTR_LDP: u8 = 0b11_000_100; +pub const INSTR_LDS: u8 = 0b11_000_101; +pub const INSTR_LDG: u8 = 0b11_000_110; +pub const INSTR_LDC: u8 = 0b11_000_111; +pub const INSTR_LDM: u8 = 0b11_001_000; + +pub const INSTR_PCVS: u8 = 0b11_010_000; -pub const INSTR_PCVS: u8 = 0b11_001_000; // NB: For now we prohibit all other ISAE than this one. More ISAEs can be // allowed in a future with fast-forwards. pub use aluvm::isa::opcodes::{INSTR_ISAE_FROM, INSTR_ISAE_TO}; -use amplify::Wrapper; +use amplify::num::{u24, u4}; use crate::validation::OpInfo; use crate::{Assign, TypedState}; @@ -43,6 +55,68 @@ use crate::{Assign, TypedState}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] pub enum RgbIsa { + /// Counts number of inputs (previous state entries) of the provided type + /// and assigns the number to the destination `a32` register. + #[display("cnp {0},a32{1}")] + CnP(u16, Reg16), + + /// Counts number of outputs (owned state entries) of the provided type + /// and assigns the number to the destination `a32` register. + #[display("cns {0},a32{1}")] + CnS(u16, Reg16), + + /// Counts number of inputs (previous state entries) of the provided type + /// and assigns the number to the destination `a8` register. + #[display("cng {0},a8{1}")] + CnG(u16, Reg16), + + /// Counts number of inputs (previous state entries) of the provided type + /// and assigns the number to the destination `a32` register. + #[display("cnc {0},a32{1}")] + CnC(u16, Reg16), + + /// 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 concealed sets destination to `None`. + /// Does not modify content of `st0` register. + #[display("ldp {0},{1},{2}")] + LdP(u16, u24, RegS), + + /// Loads owned 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 concealed sets destination to `None`. + /// Does not modify content of `st0` register. + #[display("lds {0},{1},{2}")] + LdS(u16, u24, RegS), + + /// 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 or concealed sets destination to `None`. + /// Does not modify content of `st0` register. + #[display("ldg {0},{1},{2}")] + LdG(u16, 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. + /// + /// If the state is absent or concealed sets destination to `None`. + /// Does not modify content of `st0` register. + #[display("ldc {0},{1},{2}")] + LdC(u16, u24, RegS), + + /// Loads operation metadata into a register provided in the third argument. + /// + /// If the operation doesn't have metadata sets destination to `None`. + /// Does not modify content of `st0` register. + #[display("ldm {0}")] + LdM(RegS), + /// Verify sum of pedersen commitments from inputs and outputs. /// /// The only argument specifies owned state type for the sum operation. If @@ -59,15 +133,6 @@ pub enum RgbIsa { /// Verifies corrected sum of pedersen commitments adding a value taken from `RegR` to the list /// of inputs (negatives). PcCs(u16, RegR), - - /// Loads owned state into a register. - LdOs(), - - /// Loads global state item into a register. - LdGs(), - - /// Loads operation info into a string register. - LdOp(), */ /// All other future unsupported operations, which must set `st0` to /// `false`. @@ -140,6 +205,12 @@ impl InstructionSet for RgbIsa { impl Bytecode for RgbIsa { fn byte_count(&self) -> u16 { match self { + RgbIsa::CnP(_, _) | RgbIsa::CnS(_, _) | RgbIsa::CnG(_, _) | RgbIsa::CnC(_, _) => 3, + + RgbIsa::LdP(_, _, _) | RgbIsa::LdS(_, _, _) | RgbIsa::LdC(_, _, _) => 6, + RgbIsa::LdG(_, _, _) => 4, + RgbIsa::LdM(_) => 1, + RgbIsa::PcVs(_) => 2, RgbIsa::Fail(_) => 0, } @@ -149,7 +220,19 @@ impl Bytecode for RgbIsa { fn instr_byte(&self) -> u8 { match self { - Self::PcVs(_) => INSTR_PCVS, + RgbIsa::CnP(_, _) => INSTR_CNP, + RgbIsa::CnS(_, _) => INSTR_CNS, + RgbIsa::CnG(_, _) => INSTR_CNG, + RgbIsa::CnC(_, _) => INSTR_CNC, + + RgbIsa::LdP(_, _, _) => INSTR_LDP, + RgbIsa::LdS(_, _, _) => INSTR_LDS, + RgbIsa::LdG(_, _, _) => INSTR_LDG, + RgbIsa::LdC(_, _, _) => INSTR_LDC, + RgbIsa::LdM(_) => INSTR_LDM, + + RgbIsa::PcVs(_) => INSTR_PCVS, + RgbIsa::Fail(other) => *other, } } @@ -157,6 +240,55 @@ impl Bytecode for RgbIsa { fn encode_args(&self, writer: &mut W) -> Result<(), BytecodeError> where W: Write { match self { + RgbIsa::CnP(state_type, reg) => { + writer.write_u16(*state_type)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::CnS(state_type, reg) => { + writer.write_u16(*state_type)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::CnG(state_type, reg) => { + writer.write_u16(*state_type)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::CnC(state_type, reg) => { + writer.write_u16(*state_type)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::LdP(state_type, index, reg) => { + writer.write_u16(*state_type)?; + writer.write_u24(*index)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::LdS(state_type, index, reg) => { + writer.write_u16(*state_type)?; + writer.write_u24(*index)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::LdG(state_type, index, reg) => { + writer.write_u16(*state_type)?; + writer.write_u8(*index)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::LdC(state_type, index, reg) => { + writer.write_u16(*state_type)?; + writer.write_u24(*index)?; + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::LdM(reg) => { + writer.write_u4(reg)?; + writer.write_u4(u4::ZERO)?; + } + RgbIsa::PcVs(state_type) => writer.write_u16(*state_type)?, RgbIsa::Fail(_) => {} } @@ -169,6 +301,53 @@ impl Bytecode for RgbIsa { R: Read, { Ok(match reader.read_u8()? { + INSTR_CNP => { + let i = Self::CnP(reader.read_u16()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_CNS => { + let i = Self::CnS(reader.read_u16()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_CNG => { + let i = Self::CnG(reader.read_u16()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_CNC => { + let i = Self::CnC(reader.read_u16()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + + INSTR_LDP => { + let i = Self::LdP(reader.read_u16()?, reader.read_u24()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_LDS => { + let i = Self::LdS(reader.read_u16()?, reader.read_u24()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_LDG => { + let i = Self::LdG(reader.read_u16()?, reader.read_u8()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_LDC => { + let i = Self::LdC(reader.read_u16()?, reader.read_u24()?, reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_LDM => { + let i = Self::LdM(reader.read_u4()?.into()); + reader.read_u4()?; // Discard garbage bits + i + } + INSTR_PCVS => Self::PcVs(reader.read_u16()?), other => Self::Fail(other), })