Skip to content

Commit

Permalink
Implement all instructions, add DUP check
Browse files Browse the repository at this point in the history
  • Loading branch information
matsakiv committed Jul 27, 2023
1 parent 09a0644 commit 4b3d94a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 80 deletions.
2 changes: 1 addition & 1 deletion michelson_vm/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ mod lambda;
mod math;
mod scope;
mod stack;
mod tickets;
mod tickets;
5 changes: 5 additions & 0 deletions michelson_vm/src/instructions/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ impl PureInterpreter for Dup {
}
// TODO: check if copyable
let res = stack.dup_at(n - 1)?;

if let StackItem::Ticket(_) = res {
return err_unsupported!("TICKETS DUP");
}

stack.push(res)
}
}
Expand Down
145 changes: 88 additions & 57 deletions michelson_vm/src/instructions/tickets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,119 @@
//
// SPDX-License-Identifier: MIT

use tezos_michelson::michelson::data::instructions::{
Ticket, ReadTicket, SplitTicket, JoinTickets,
use tezos_michelson::michelson::{
data::instructions::{JoinTickets, ReadTicket, SplitTicket, Ticket},
types,
};

use crate::{
err_mismatch,
interpreter::{
ContextInterpreter, InterpreterContext, PureInterpreter,
},
//pop_cast,
interpreter::{PureInterpreter, ScopedInterpreter},
pop_cast,
stack::Stack,
Result, types::{AddressItem, NatItem, StackItem, TicketItem, PairItem, OptionItem},
typechecker::check_type_comparable,
types::{AddressItem, OptionItem, PairItem, StackItem, TicketItem},
OperationScope, Result,
};

impl ContextInterpreter for Ticket {
fn execute(&self, stack: &mut Stack, context: &mut impl InterpreterContext) -> Result<()> {
impl ScopedInterpreter for Ticket {
fn execute(&self, stack: &mut Stack, scope: &OperationScope) -> Result<()> {
let identifier = stack.pop()?;
let amount = stack.pop()?;

// TODO: compare amount with zero
// TODO: convert StackItem identifier to Micheline
// TODO: get Type for identifier
// TODO: get self address
// TODO: save balance info to context?

//stack.push(StackItem::Ticket(TicketItem::new()));
Ok(())
let identifier_ty = identifier.get_type()?;
check_type_comparable(&identifier_ty)?;

let amount = pop_cast!(stack, Nat);

if amount.is_zero() {
let ty = types::ticket(identifier_ty);
return stack.push(StackItem::Option(OptionItem::None(ty)));
}

let ticket = TicketItem {
source: AddressItem::new(scope.self_address.clone().into()),
identifier: Box::new(identifier),
amount: amount,
};

stack.push(StackItem::Option(OptionItem::Some(Box::new(ticket.into()))))
}
}

impl PureInterpreter for ReadTicket {
fn execute(&self, stack: &mut Stack) -> Result<()> {
let ticket_item = stack.pop()?;
let ticket = match ticket_item {
StackItem::Ticket(ticket) => ticket,
item => return err_mismatch!("Ticket", item)
};
let ticket = pop_cast!(stack, Ticket);

let source = StackItem::Address(AddressItem::new(ticket.source));
let identifier = ticket.identifier; // TODO: identifier to StackItem
let amount = StackItem::Nat(NatItem::new(ticket.amount));

let pair = PairItem::from_items(vec![source, identifier, amount])?;
let pair = PairItem::from_items(vec![
ticket.source.clone().into(),
*ticket.identifier.clone(),
ticket.amount.clone().into(),
])?;

stack.push(StackItem::Pair(pair));
stack.push(ticket_item); // return ticket back to stack
Ok(())
stack.push(ticket.into())?; // return ticket back to stack
stack.push(pair.into())
}
}

impl ContextInterpreter for SplitTicket {
fn execute(&self, stack: &mut Stack, context: &mut impl InterpreterContext) -> Result<()> {
let ticket = stack.pop()?; // ticket
let split_pair = stack.pop()?; // pair nat nat
impl PureInterpreter for SplitTicket {
fn execute(&self, stack: &mut Stack) -> Result<()> {
let ticket = pop_cast!(stack, Ticket); // ticket
let pair_n1_n2 = pop_cast!(stack, Pair); // pair nat nat

// TODO: if n + m != ticket.amount or n == 0 or m == 0 return none
stack.push(StackItem::Option(OptionItem::None()));
let (n1, n2) = match pair_n1_n2.unpair() {
(StackItem::Nat(n1), StackItem::Nat(n2)) => (n1, n2),
(s1, s2) => {
return err_mismatch!(
"Pair Nat Nat",
StackItem::Pair(PairItem::new(s1, s2))
)
}
};

// TODO: else return pair (ticket_n, ticket_m)
stack.push(StackItem::Option(OptionItem::Some()));

// TODO: update balance in context?
if n1.is_zero() || n2.is_zero() || n1.clone() + n2.clone() != ticket.amount {
let ty = types::pair(vec![types::nat(), types::nat()]);
return stack.push(StackItem::Option(OptionItem::None(ty)));
}

Ok(())
let ticket_1 = TicketItem {
source: ticket.source.clone(),
identifier: ticket.identifier.clone(),
amount: n1,
};
let ticket_2 = TicketItem {
source: ticket.source,
identifier: ticket.identifier,
amount: n2,
};
let pair = PairItem::new(ticket_1.into(), ticket_2.into());

stack.push(StackItem::Option(OptionItem::Some(Box::new(pair.into()))))
}
}

impl ContextInterpreter for JoinTickets {
fn execute(&self, stack: &mut Stack, context: &mut impl InterpreterContext) -> Result<()> {
let tickets = stack.pop()?; // tickets pair
// TODO: get ticket_a
// TODO: get ticket_b
// TODO: compare sources and identifiers (and identifiers types?)
impl PureInterpreter for JoinTickets {
fn execute(&self, stack: &mut Stack) -> Result<()> {
let tickets = pop_cast!(stack, Pair); // tickets pair
let (ticket_1, ticket_2) = match tickets.unpair() {
(StackItem::Ticket(ticket_1), StackItem::Ticket(ticket_2)) => (ticket_1, ticket_2),
(s1, s2) => {
return err_mismatch!(
"Pair Ticket Ticket",
StackItem::Pair(PairItem::new(s1, s2))
)
}
};

// TODO: if ticket_a.source != ticket_b.source or ticket_a.identifier != ticket_b.identifier
stack.push(StackItem::Option(OptionItem::None()));
if ticket_1.source != ticket_2.source || *ticket_1.identifier != *ticket_2.identifier {
let ty = types::ticket(ticket_1.identifier.get_type()?);
return stack.push(StackItem::Option(OptionItem::None(ty)));
}

// TODO: OR otherwise return Some(ticket)
stack.push(StackItem::Option(OptionItem::Some()));

// TODO: update balance in context?
let ticket = TicketItem {
source: ticket_1.source,
identifier: ticket_1.identifier,
amount: ticket_1.amount + ticket_2.amount,
};

Ok(())
stack.push(StackItem::Option(OptionItem::Some(Box::new(ticket.into()))))
}
}
}
4 changes: 4 additions & 0 deletions michelson_vm/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ impl Interpreter for Instruction {
Instruction::Blake2B(instr) => instr.execute(stack),
Instruction::HashKey(instr) => instr.execute(stack),
Instruction::CheckSignature(instr) => instr.execute(stack),
Instruction::Ticket(instr) => instr.execute(stack, scope),
Instruction::ReadTicket(instr) => instr.execute(stack),
Instruction::SplitTicket(instr) => instr.execute(stack),
Instruction::JoinTickets(instr) => instr.execute(stack),
_ => err_unsupported!(self.format()),
};
trace_exit!(res.as_ref().err(), format!("Len {}", &stack.len()).as_str());
Expand Down
9 changes: 4 additions & 5 deletions michelson_vm/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ pub mod option;
pub mod or;
pub mod pair;
pub mod set;
pub mod timestamp;
pub mod ticket;
pub mod timestamp;

use derive_more::{Display, From, TryInto};
use ibig::{IBig, UBig};
Expand Down Expand Up @@ -161,10 +161,9 @@ pub enum BigMapItem {

#[derive(Debug, Clone, PartialEq)]
pub struct TicketItem {
pub source: Address,
pub identifier: Micheline,
pub identifier_type: Type,
pub amount: UBig,
pub source: AddressItem,
pub identifier: Box<StackItem>,
pub amount: NatItem,
}

#[derive(Debug, Display, Clone, From, TryInto, PartialEq, PartialOrd, Eq, Ord)]
Expand Down
6 changes: 5 additions & 1 deletion michelson_vm/src/types/nat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MIT

use ibig::{IBig, UBig};
use ibig::{ubig, IBig, UBig};
use std::fmt::Display;
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
use tezos_michelson::michelson::{
Expand Down Expand Up @@ -40,6 +40,10 @@ impl NatItem {
pub fn int(self) -> IntItem {
IntItem(IBig::from(self.0))
}

pub fn is_zero(&self) -> bool {
self.0 == ubig!(0)
}
}

impl Display for NatItem {
Expand Down
30 changes: 14 additions & 16 deletions michelson_vm/src/types/ticket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,31 @@

use std::fmt::Display;

use ibig::UBig;
use tezos_core::types::encoded::Address;
use tezos_michelson::{michelson::types::{self, Type}, micheline::Micheline};
use tezos_michelson::michelson::types::{self, Type};

use crate::{
types::TicketItem,
Result,
};
use crate::{types::TicketItem, Result};

use super::{AddressItem, NatItem, StackItem};

impl TicketItem {
pub fn new(source: Address, identifier: Micheline, identifier_type: Type, amount: UBig) -> Self{
pub fn new(source: AddressItem, identifier: StackItem, amount: NatItem) -> Self {
Self {
source,
identifier,
identifier_type,
amount,
source: source,
identifier: Box::new(identifier),
amount: amount,
}
}

pub fn get_type(&self) -> Result<Type> {
Ok(types::ticket(self.identifier_type.clone()))
Ok(types::ticket(self.identifier.get_type()?))
}

}

impl Display for TicketItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("({:?} {:?} {})", self.source, self.identifier, self.amount))
f.write_fmt(format_args!(
"({:?} {:?} {})",
self.source, self.identifier, self.amount
))
}
}
}

0 comments on commit 4b3d94a

Please sign in to comment.