mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 13:56:58 +03:00
mess
This commit is contained in:
parent
1fbc16ce24
commit
aa37895d91
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -823,6 +823,15 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "disassembler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"leo-ast",
|
||||
"leo-span",
|
||||
"snarkvm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@ -1380,6 +1389,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"snarkvm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -41,7 +41,8 @@ members = [
|
||||
"docs/grammar",
|
||||
"errors",
|
||||
"leo/package",
|
||||
"tests/test-framework"
|
||||
"tests/test-framework",
|
||||
"utils/disassembler"
|
||||
]
|
||||
|
||||
[workspace.dependencies.snarkvm]
|
||||
|
@ -18,6 +18,9 @@ license = "GPL-3.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.69"
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
|
||||
[dependencies.leo-errors]
|
||||
path = "../../errors"
|
||||
version = "=1.10.0"
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use leo_errors::Result;
|
||||
use leo_span::{Span, Symbol};
|
||||
use snarkvm::console::program::Identifier as IdentifierCore;
|
||||
|
||||
use crate::{simple_node_impl, Node, NodeID};
|
||||
use serde::{
|
||||
@ -28,6 +29,9 @@ use serde::{
|
||||
Serialize,
|
||||
Serializer,
|
||||
};
|
||||
use snarkvm::{
|
||||
prelude::Network,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
@ -152,3 +156,11 @@ impl<'de> Deserialize<'de> for Identifier {
|
||||
deserializer.deserialize_str(IdentifierVisitor)
|
||||
}
|
||||
}
|
||||
impl<N: Network> From<IdentifierCore<N>> for Identifier {
|
||||
fn from(id: IdentifierCore<N>) -> Self {
|
||||
let id_str = id.to_string();
|
||||
dbg!(id_str.clone());
|
||||
let a = "Dummy";
|
||||
Self { name: Symbol::intern(a), span: Default::default(), id: Default::default() }
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ use crate::Identifier;
|
||||
|
||||
use core::fmt;
|
||||
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use snarkvm::{console::program::ProgramID, prelude::Network};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// An identifier for a program that is eventually deployed to the network.
|
||||
@ -92,3 +93,9 @@ impl<'de> Deserialize<'de> for ProgramId {
|
||||
deserializer.deserialize_str(ProgramIdVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Network> From<ProgramID<N>> for ProgramId {
|
||||
fn from(program: ProgramID<N>) -> Self {
|
||||
Self { name: Identifier::from(*program.name()), network: Identifier::from(*program.network()) }
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,20 @@
|
||||
pub mod member;
|
||||
pub use member::*;
|
||||
|
||||
use crate::{Identifier, Node, NodeID};
|
||||
use crate::{Identifier, Mode, Node, NodeID, Type};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
use snarkvm::{
|
||||
console::program::{RecordType, StructType},
|
||||
prelude::{
|
||||
EntryType::{Private, Public, Constant},
|
||||
Network,
|
||||
},
|
||||
};
|
||||
|
||||
/// A struct type definition, e.g., `struct Foo { my_field: Bar }`.
|
||||
/// In some languages these are called `struct`s.
|
||||
///
|
||||
@ -77,3 +85,51 @@ impl fmt::Display for Struct {
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(Struct);
|
||||
|
||||
// impl<N: Network> From<&StructType<N>> for Struct {
|
||||
// fn from(input: &StructType<N>) -> Self {
|
||||
// Self {
|
||||
// identifier: Identifier::from(input.name()),
|
||||
// members: input
|
||||
// .members()
|
||||
// .iter()
|
||||
// .map(|(id, type_)| Member {
|
||||
// mode: Mode::None,
|
||||
// identifier: Identifier::from(id),
|
||||
// type_: Type::from(type_),
|
||||
// span: Default::default(),
|
||||
// id: Default::default(),
|
||||
// })
|
||||
// .collect(),
|
||||
// is_record: false,
|
||||
// span: Default::default(),
|
||||
// id: Default::default(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl<N: Network> From<&RecordType<N>> for Struct {
|
||||
// fn from(input: &RecordType<N>) -> Self {
|
||||
// Self {
|
||||
// identifier: Identifier::from(input.name()),
|
||||
// members: input
|
||||
// .entries()
|
||||
// .iter()
|
||||
// .map(|(id, entry)| Member {
|
||||
// mode: Mode::None,
|
||||
// identifier: Identifier::from(id),
|
||||
// type_: match entry {
|
||||
// Public(t) => Type::from(t),
|
||||
// Private(t) => Type::from(t),
|
||||
// Constant(t) => Type::from(t),
|
||||
// },
|
||||
// span: Default::default(),
|
||||
// id: Default::default(),
|
||||
// })
|
||||
// .collect(),
|
||||
// is_record: true,
|
||||
// span: Default::default(),
|
||||
// id: Default::default(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -21,7 +21,8 @@ pub use finalize_stub::*;
|
||||
pub mod function_stub;
|
||||
pub use function_stub::*;
|
||||
|
||||
use crate::{ConstDeclaration, Identifier, Mapping, ProgramId, Struct};
|
||||
|
||||
use crate::{ConstDeclaration, Mapping, ProgramId, Struct};
|
||||
use leo_span::{Span, Symbol};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -30,7 +31,7 @@ use std::fmt;
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Stub {
|
||||
/// A vector of imported programs.
|
||||
pub imports: Vec<Identifier>,
|
||||
pub imports: Vec<ProgramId>,
|
||||
/// The stub id
|
||||
pub stub_id: ProgramId,
|
||||
/// A vector of const definitions.
|
||||
|
@ -14,10 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ArrayType, Identifier, IntegerType, MappingType, TupleType};
|
||||
use crate::{ArrayType, common, Identifier, IntegerType, MappingType, TupleType};
|
||||
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use snarkvm::prelude::{
|
||||
Network,
|
||||
PlaintextType,
|
||||
PlaintextType::{Array, Literal, Struct},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// Explicit type used for defining a variable or expression type
|
||||
|
0
tests/expectations/parser/program/stub.out
Normal file
0
tests/expectations/parser/program/stub.out
Normal file
34
tests/tests/compiler/function/test.leo
Normal file
34
tests/tests/compiler/function/test.leo
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
*/
|
||||
|
||||
program test.aleo {
|
||||
struct message {
|
||||
sender: u8,
|
||||
object: u8,
|
||||
}
|
||||
mapping balances: u8 => u8;
|
||||
|
||||
transition a(arg1: message) -> message {
|
||||
return message {
|
||||
sender: 1u8,
|
||||
object: 1u8,
|
||||
};
|
||||
}
|
||||
|
||||
function b(arg1: message) -> message {
|
||||
return message {
|
||||
sender: 1u8,
|
||||
object: 1u8,
|
||||
};
|
||||
}
|
||||
|
||||
function c(arg1: balances) -> balances {
|
||||
return arg1;
|
||||
}
|
||||
|
||||
transition d(arg1: balances) -> balances {
|
||||
return arg1;
|
||||
}
|
||||
}
|
17
utils/disassembler/Cargo.toml
Normal file
17
utils/disassembler/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "disassembler"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
|
||||
[dependencies.leo-ast]
|
||||
path = "../../compiler/ast"
|
||||
version = "=1.9.4"
|
||||
|
||||
[dependencies.leo-span]
|
||||
path = "../../compiler/span"
|
||||
version = "1.9.3"
|
383
utils/disassembler/src/main.rs
Normal file
383
utils/disassembler/src/main.rs
Normal file
@ -0,0 +1,383 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use snarkvm::{
|
||||
console::network::Testnet3,
|
||||
prelude::{Itertools, Network, RegisterType, ValueType},
|
||||
synthesizer::{
|
||||
program::{CommandTrait, InstructionTrait, Program, ProgramCore},
|
||||
Command,
|
||||
Instruction,
|
||||
},
|
||||
};
|
||||
use snarkvm::console::program::Identifier as IdentifierCore;
|
||||
use leo_span::Symbol;
|
||||
use std::{ops::Add, str::FromStr};
|
||||
|
||||
use leo_ast::{Identifier, ProgramId, Struct, Stub};
|
||||
use leo_ast::Type::Identifier as IdentifierType;
|
||||
|
||||
type CurrentNetwork = Testnet3;
|
||||
|
||||
fn main() {
|
||||
let a = Symbol::intern("aleo");
|
||||
}
|
||||
|
||||
// fn old() {
|
||||
// // let credits_aleo =
|
||||
// // std::fs::read_to_string("/Users/evanschott/work/leo/utils/disassembler/src/tests/credits.aleo").unwrap();
|
||||
// // println!("{}", code_gen(credits_aleo));
|
||||
// let aleo_prog_1 = r"import credits.aleo;
|
||||
//
|
||||
// import battleship.aleo;
|
||||
// import juice.aleo;
|
||||
//
|
||||
// program to_parse.aleo;
|
||||
//
|
||||
// function new_board_state:
|
||||
// input r0 as u64.private;
|
||||
// input r1 as address.private;
|
||||
// cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
// output r2 as board_state.record;
|
||||
//
|
||||
// closure add_up:
|
||||
// input r0 as u8;
|
||||
// input r1 as u8;
|
||||
// add r0 r1 into r2;
|
||||
// output r2 as u8;
|
||||
//
|
||||
// function transfer_public_to_private:
|
||||
// input r0 as address.private;
|
||||
// input r1 as u64.public;
|
||||
// cast r0 r1 into r2 as credits.record;
|
||||
// async transfer_public_to_private self.caller r1 into r3;
|
||||
// output r2 as credits.record;
|
||||
// output r3 as credits.aleo/transfer_public_to_private.future;
|
||||
//
|
||||
// finalize transfer_public_to_private:
|
||||
// input r0 as address.public;
|
||||
// input r1 as u64.public;
|
||||
// get.or_use account[r0] 0u64 into r2;
|
||||
// sub r2 r1 into r3;
|
||||
// set r3 into account[r0];
|
||||
// ";
|
||||
// let program = Program::<CurrentNetwork>::from_str(aleo_prog_1);
|
||||
// match program {
|
||||
// Ok(p) => {
|
||||
// let disassembled = disassemble(p);
|
||||
// println!("{}", disassembled)
|
||||
// }
|
||||
// Err(e) => {
|
||||
// println!("{}", e);
|
||||
// }
|
||||
// }
|
||||
// // println!("{}", disassemble(Program::<CurrentNetwork>::from_str(aleo_prog_1).unwrap()));
|
||||
// }
|
||||
|
||||
// fn disassemble<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>(
|
||||
// program: ProgramCore<N, Instruction, Command>,
|
||||
// ) -> Stub {
|
||||
// dbg!(program.records());
|
||||
//
|
||||
// let mut stub = Stub {
|
||||
// imports: Vec::new(),
|
||||
// stub_id: ProgramId::from(program.id()),
|
||||
// consts: Vec::new(),
|
||||
// structs: Vec::new(),
|
||||
// mappings: Vec::new(),
|
||||
// functions: Vec::new(),
|
||||
// span: Default::default(),
|
||||
// };
|
||||
//
|
||||
//
|
||||
// let structs = program.structs().iter().map(|(id,s)| {
|
||||
// (Identifier::from(id).name, Struct::from(s))
|
||||
// }).collect_vec();
|
||||
// let records = program.records().iter().map(|(id,s)| {
|
||||
// dbg!(id.clone());
|
||||
// dbg!(s);
|
||||
// println!("{}", id.clone());
|
||||
// let id_str = id.clone().to_string();
|
||||
// let id_sym = Symbol::intern(&id_str);
|
||||
// ((id_sym, Struct::from(s)))
|
||||
// }).collect_vec();
|
||||
//
|
||||
//
|
||||
// stub
|
||||
//
|
||||
// // Stub {
|
||||
// // imports: program.imports().into_iter().map(|(id, import)| ProgramId::from(id)).collect(),
|
||||
// // stub_id: ProgramId::from(program.id()),
|
||||
// // consts: Vec::new(),
|
||||
// // structs: [structs,records].concat(),
|
||||
// // mappings: Vec::new(),
|
||||
// // functions: Vec::new(), // TODO: Add functions AND closures
|
||||
// // span: Default::default(),
|
||||
// // }
|
||||
// }
|
||||
|
||||
fn print_visibility<N: Network>(visibility: &ValueType<N>) -> String {
|
||||
match visibility {
|
||||
ValueType::Public(_) => "public ".to_string(),
|
||||
_ => "".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_transition_input<N: Network>(input: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
format!("{}a{}: {}", print_visibility(input), index + 1, print_transition_value(input, index, len))
|
||||
}
|
||||
|
||||
fn print_transition_value<N: Network>(value: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
let value_str = match value {
|
||||
ValueType::Constant(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Public(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Private(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Record(id) => format!("{}", id.to_string()),
|
||||
ValueType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
|
||||
ValueType::Future(_) => panic!("Futures must be filtered out by this stage"),
|
||||
};
|
||||
let situational_comma = if index == len - 1 { "" } else { ", " };
|
||||
format!("{}{}", value_str, situational_comma)
|
||||
}
|
||||
|
||||
fn print_transition_output<N: Network>(output: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
let (left, right) = if len == 1 {
|
||||
(" -> ", "")
|
||||
} else if index == 0 {
|
||||
(" -> (", "")
|
||||
} else if index == len - 1 {
|
||||
("", ")")
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
format!("{}{}{}", left, print_transition_value(output, index, len), right)
|
||||
}
|
||||
|
||||
fn print_function_output<N: Network>(output: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
let (left, right) = if len == 1 {
|
||||
(" -> ", "")
|
||||
} else if index == 0 {
|
||||
(" -> (", "")
|
||||
} else if index == len - 1 {
|
||||
("", ")")
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
format!("{}{}{}", left, print_function_value(output, index, len), right)
|
||||
}
|
||||
|
||||
fn print_function_input<N: Network>(input: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
format!("a{}: {}", index + 1, print_function_value(input, index, len))
|
||||
}
|
||||
|
||||
fn print_function_value<N: Network>(value: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
let value_str = match value {
|
||||
RegisterType::Plaintext(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
RegisterType::Record(val) => format!("{}", val.to_string()),
|
||||
RegisterType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
|
||||
RegisterType::Future(_) => panic!("Futures must be filtered out by this stage"),
|
||||
};
|
||||
let situational_comma = if index == len - 1 { "" } else { ", " };
|
||||
format!("{}{}", value_str, situational_comma)
|
||||
}
|
||||
|
||||
fn code_gen(input: String) -> String {
|
||||
// Parse a new program.
|
||||
let result = Program::<CurrentNetwork>::from_str(&input).unwrap();
|
||||
|
||||
let mut output = format!("stub {}.aleo {{", result.id().name());
|
||||
|
||||
// Write imports
|
||||
output.push_str(
|
||||
&result.imports().into_iter().map(|(name, _)| format!("\n import {};\n", name)).collect::<String>(),
|
||||
);
|
||||
|
||||
// Write records
|
||||
output.push_str(
|
||||
&result
|
||||
.records()
|
||||
.into_iter()
|
||||
.map(|(name, fields)| {
|
||||
format!("\n record {} {{\n owner: address,\n", name).add(
|
||||
&(fields
|
||||
.entries()
|
||||
.into_iter()
|
||||
.map(|(id, entry_type)| {
|
||||
if entry_type.plaintext_type().to_string() == "boolean" {
|
||||
return format!(" {}: bool,\n", id);
|
||||
} else {
|
||||
format!(" {}: {},\n", id, entry_type.plaintext_type().to_string())
|
||||
}
|
||||
})
|
||||
.collect::<String>()
|
||||
+ " }\n")
|
||||
.to_string(),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Write transitions
|
||||
output.push_str(
|
||||
&result
|
||||
.functions()
|
||||
.into_iter()
|
||||
.map(|(name, value)| {
|
||||
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
|
||||
|
||||
// Can assume that last output is a future if the function has associated finalize
|
||||
let outputs_vec = if value.finalize_logic().is_some() {
|
||||
outputs[..outputs.len() - 1].iter().collect_vec()
|
||||
} else {
|
||||
outputs.iter().collect_vec()
|
||||
};
|
||||
let len = outputs_vec.len();
|
||||
|
||||
format!("\n transition {}(", name).add(
|
||||
&(inputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| print_transition_input(&input.value_type(), index, inputs.len()))
|
||||
.collect::<String>()
|
||||
+ ")")
|
||||
.add(
|
||||
&(outputs_vec
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, output)| print_transition_output(&output.value_type(), index, len))
|
||||
.collect::<String>()
|
||||
+ ";\n")
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Write functions
|
||||
output.push_str(
|
||||
&result
|
||||
.closures()
|
||||
.into_iter()
|
||||
.map(|(name, value)| {
|
||||
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
|
||||
let len = outputs.len();
|
||||
|
||||
format!("\n function {}(", name).add(
|
||||
&(inputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| print_function_input(&input.register_type(), index, inputs.len()))
|
||||
.collect::<String>()
|
||||
+ ")")
|
||||
.add(
|
||||
&(outputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, output)| print_function_output(&output.register_type(), index, len))
|
||||
.collect::<String>()
|
||||
+ ";\n")
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Append final closing bracket
|
||||
output.push_str("}\n");
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn code_gen_test() {
|
||||
let aleo_prog_1 = r"import credits.aleo;
|
||||
|
||||
import battleship.aleo;
|
||||
import juice.aleo;
|
||||
|
||||
program to_parse.aleo;
|
||||
|
||||
record board_state:
|
||||
owner as address.private;
|
||||
hits_and_misses as u64.private;
|
||||
played_tiles as u64.private;
|
||||
ships as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
game_started as boolean.private;
|
||||
|
||||
function new_board_state:
|
||||
input r0 as u64.private;
|
||||
input r1 as address.private;
|
||||
cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
closure add_up:
|
||||
input r0 as u8;
|
||||
input r1 as u8;
|
||||
add r0 r1 into r2;
|
||||
output r2 as u8;
|
||||
|
||||
function transfer_public_to_private:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.public;
|
||||
cast r0 r1 into r2 as credits.record;
|
||||
async transfer_public_to_private self.caller r1 into r3;
|
||||
output r2 as credits.record;
|
||||
output r3 as credits.aleo/transfer_public_to_private.future;
|
||||
|
||||
finalize transfer_public_to_private:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
sub r2 r1 into r3;
|
||||
set r3 into account[r0];
|
||||
";
|
||||
let leo_stub_1: &str = r"stub to_parse.aleo {
|
||||
import credits.aleo;
|
||||
|
||||
import battleship.aleo;
|
||||
|
||||
import juice.aleo;
|
||||
|
||||
record board_state {
|
||||
owner: address,
|
||||
hits_and_misses: u64,
|
||||
played_tiles: u64,
|
||||
ships: u64,
|
||||
player_1: address,
|
||||
player_2: address,
|
||||
game_started: bool,
|
||||
}
|
||||
|
||||
transition new_board_state(a1: u64, a2: address) -> board_state;
|
||||
|
||||
transition transfer_public_to_private(a1: address, public a2: u64) -> credits;
|
||||
|
||||
function add_up(a1: u8, a2: u8) -> u8;
|
||||
}
|
||||
";
|
||||
let code_gen_1 = code_gen(aleo_prog_1.to_string());
|
||||
assert_eq!(code_gen_1, leo_stub_1);
|
||||
|
||||
}
|
||||
}
|
845
utils/disassembler/src/tests/credits.aleo
Normal file
845
utils/disassembler/src/tests/credits.aleo
Normal file
@ -0,0 +1,845 @@
|
||||
// Copyright (C) 2019-2023 Aleo Systems Inc.
|
||||
// This file is part of the snarkVM library.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
program credits.aleo;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
/// The `committee` mapping contains the active validator set and their corresponding stake.
|
||||
mapping committee:
|
||||
// The key represents the address of the validator.
|
||||
key as address.public;
|
||||
// The value represents the committee state of the validator.
|
||||
value as committee_state.public;
|
||||
|
||||
// The `committee_state` struct tracks the total stake of the validator, and whether they are open to stakers.
|
||||
struct committee_state:
|
||||
// The amount of microcredits bonded to the validator, by the validator and its delegators.
|
||||
microcredits as u64;
|
||||
// The boolean flag indicating if the validator is open to stakers.
|
||||
is_open as boolean;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `bonded` mapping represents the amount of microcredits that are currently bonded.
|
||||
mapping bonded:
|
||||
// The key represents the address of the staker, which includes the validators and their delegators.
|
||||
key as address.public;
|
||||
// The value represents the bond state.
|
||||
value as bond_state.public;
|
||||
|
||||
// The `bond_state` struct tracks the amount of microcredits that are currently bonded to the specified validator.
|
||||
struct bond_state:
|
||||
// The address of the validator.
|
||||
validator as address;
|
||||
// The amount of microcredits that are currently bonded to the specified validator.
|
||||
microcredits as u64;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `unbonding` mapping contains a set of stakers with their unbonding microcredits and unlock height.
|
||||
mapping unbonding:
|
||||
// The key represents the address of the staker, which includes the validators and their delegators.
|
||||
key as address.public;
|
||||
// The value represents the unbond state.
|
||||
value as unbond_state.public;
|
||||
|
||||
// The `unbond_state` struct tracks the microcredits that are currently unbonding, along with the unlock height.
|
||||
struct unbond_state:
|
||||
// The amount of microcredits that are currently unbonding.
|
||||
microcredits as u64;
|
||||
// The block height at which the unbonding will be complete, and can be claimed.
|
||||
height as u32;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `account` mapping is used to store credits publicly.
|
||||
mapping account:
|
||||
// The key represents the address of the owner.
|
||||
key as address.public;
|
||||
// The value represents the amount of public microcredits that belong to the specified owner.
|
||||
value as u64.public;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `credits` record is used to store credits privately.
|
||||
record credits:
|
||||
// The address of the owner.
|
||||
owner as address.private;
|
||||
// The amount of private microcredits that belong to the specified owner.
|
||||
microcredits as u64.private;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// This function allows any staker to bond their microcredits to a validator.
|
||||
// The corresponding functions for 'bond_public' are 'unbond_public' and 'claim_unbond_public'.
|
||||
function bond_public:
|
||||
// Input the validator's address.
|
||||
input r0 as address.public;
|
||||
// Input the amount of microcredits to bond.
|
||||
input r1 as u64.public;
|
||||
|
||||
// Determine if the amount is at least one credit.
|
||||
gte r1 1_000_000u64 into r2;
|
||||
// Enforce the amount is at least one credit.
|
||||
assert.eq r2 true;
|
||||
|
||||
// Bond the specified amount of microcredits to the specified validator.
|
||||
async bond_public self.caller r0 r1 into r3;
|
||||
// Output the finalize future.
|
||||
output r3 as credits.aleo/bond_public.future;
|
||||
|
||||
finalize bond_public:
|
||||
// Input the staker's address.
|
||||
input r0 as address.public;
|
||||
// Input the validator's address.
|
||||
input r1 as address.public;
|
||||
// Input the amount of microcredits to bond.
|
||||
input r2 as u64.public;
|
||||
|
||||
// Determine whether the caller is a validator.
|
||||
is.eq r0 r1 into r3;
|
||||
// If the caller is a validator, jump to the `bond_validator` logic.
|
||||
branch.eq r3 true to bond_validator;
|
||||
// If the caller is not a validator, jump to the `bond_delegator` logic.
|
||||
branch.eq r3 false to bond_delegator;
|
||||
|
||||
/******* Bond Validator *******/
|
||||
|
||||
// Starts the `bond_validator` logic.
|
||||
position bond_validator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Construct the initial committee state.
|
||||
// Note: We set the initial 'is_open' state to 'true'.
|
||||
cast 0u64 true into r4 as committee_state;
|
||||
// Retrieve the committee state of the specified validator.
|
||||
get.or_use committee[r0] r4 into r5;
|
||||
// Ensure that the validator is open to stakers.
|
||||
assert.eq r5.is_open true;
|
||||
|
||||
// Increment the stake for the specified validator.
|
||||
add r5.microcredits r2 into r6;
|
||||
// Construct the updated committee state.
|
||||
cast r6 r5.is_open into r7 as committee_state;
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Construct the initial bond state.
|
||||
cast r1 0u64 into r8 as bond_state;
|
||||
// Get the bond state for the caller, or default to the initial bond state.
|
||||
get.or_use bonded[r0] r8 into r9;
|
||||
// Enforce the validator matches in the bond state.
|
||||
assert.eq r9.validator r1;
|
||||
|
||||
// Increment the microcredits in the bond state.
|
||||
add r9.microcredits r2 into r10;
|
||||
// Determine if the amount is at least one million credits.
|
||||
gte r10 1_000_000_000_000u64 into r11;
|
||||
// Enforce the amount is at least one million credits.
|
||||
assert.eq r11 true;
|
||||
|
||||
// Construct the updated bond state.
|
||||
cast r1 r10 into r12 as bond_state;
|
||||
|
||||
/* Account */
|
||||
|
||||
// Get the balance of the caller.
|
||||
// If the account does not exist, this finalize scope will fail.
|
||||
get account[r0] into r13;
|
||||
// Decrement the balance of the caller.
|
||||
sub r13 r2 into r14;
|
||||
|
||||
/* Writes */
|
||||
|
||||
// Update the committee state of the specified validator.
|
||||
set r7 into committee[r0];
|
||||
// Update the bond state for the caller.
|
||||
set r12 into bonded[r0];
|
||||
// Update the balance of the caller.
|
||||
set r14 into account[r0];
|
||||
|
||||
// Ends the `bond_validator` logic.
|
||||
branch.eq true true to end;
|
||||
|
||||
/******* Bond Delegator *******/
|
||||
|
||||
// Starts the `bond_delegator` logic.
|
||||
position bond_delegator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Check if the caller is a validator.
|
||||
contains committee[r0] into r15;
|
||||
// Enforce the caller is *not* a validator.
|
||||
assert.eq r15 false;
|
||||
|
||||
// Get the stake for the specified validator.
|
||||
// If the validator does not exist, this finalize scope will fail.
|
||||
get committee[r1] into r16;
|
||||
// Ensure that the validator is open to stakers.
|
||||
assert.eq r16.is_open true;
|
||||
|
||||
// Increment the stake for the specified validator.
|
||||
add r16.microcredits r2 into r17;
|
||||
// Construct the updated committee state.
|
||||
cast r17 r16.is_open into r18 as committee_state;
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Construct the initial bond state.
|
||||
cast r1 0u64 into r19 as bond_state;
|
||||
// Get the bond state for the caller, or default to the initial bond state.
|
||||
get.or_use bonded[r0] r19 into r20;
|
||||
// Enforce the validator matches in the bond state.
|
||||
assert.eq r20.validator r1;
|
||||
|
||||
// Increment the microcredits in the bond state.
|
||||
add r20.microcredits r2 into r21;
|
||||
// Determine if the amount is at least 10 credits.
|
||||
gte r21 10_000_000u64 into r22;
|
||||
// Enforce the amount is at least 10 credits.
|
||||
assert.eq r22 true;
|
||||
|
||||
// Construct the updated bond state.
|
||||
cast r1 r21 into r23 as bond_state;
|
||||
|
||||
/* Account */
|
||||
|
||||
// Get the balance of the caller.
|
||||
// If the account does not exist, this finalize scope will fail.
|
||||
get account[r0] into r24;
|
||||
// Decrement the balance of the caller.
|
||||
sub r24 r2 into r25;
|
||||
|
||||
/* Writes */
|
||||
|
||||
// Update the committee state for the specified validator.
|
||||
set r18 into committee[r1];
|
||||
// Update the bond state for the caller.
|
||||
set r23 into bonded[r0];
|
||||
// Update the balance of the caller.
|
||||
set r25 into account[r0];
|
||||
|
||||
// The terminus.
|
||||
position end;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// This function allows any staker to unbond their microcredits from a validator.
|
||||
// The corresponding functions for 'unbond_public' is 'claim_unbond_public'.
|
||||
function unbond_public:
|
||||
// Input the amount of microcredits to unbond.
|
||||
input r0 as u64.public;
|
||||
|
||||
// Unbond the specified amount of microcredits to the caller.
|
||||
async unbond_public self.caller r0 into r1;
|
||||
// Output the finalize future.
|
||||
output r1 as credits.aleo/unbond_public.future;
|
||||
|
||||
finalize unbond_public:
|
||||
// Input the staker's address.
|
||||
input r0 as address.public;
|
||||
// Input the amount of microcredits to unbond.
|
||||
input r1 as u64.public;
|
||||
|
||||
// Construct the initial unbond state.
|
||||
cast 0u64 0u32 into r2 as unbond_state;
|
||||
// Get the unbond state for the caller, or default to the initial unbond state.
|
||||
get.or_use unbonding[r0] r2 into r3;
|
||||
|
||||
// Compute the height at which the unbonding will be complete, starting from the current block.
|
||||
// Note: Calling unbond across multiple blocks before the unbonding is complete will reset the height each time.
|
||||
add block.height 360u32 into r4;
|
||||
|
||||
// Determine if the caller is a validator or delegator.
|
||||
contains committee[r0] into r5;
|
||||
|
||||
// If the caller is a validator, jump to the `unbond_validator` logic.
|
||||
branch.eq r5 true to unbond_validator;
|
||||
// If the caller is not a validator, jump to the `unbond_delegator` logic.
|
||||
branch.eq r5 false to unbond_delegator;
|
||||
|
||||
/******* Unbond Validator *******/
|
||||
|
||||
// Starts the `unbond_validator` logic.
|
||||
position unbond_validator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Get the committee state for the specified validator.
|
||||
get committee[r0] into r6;
|
||||
// Decrement the stake for the specified validator.
|
||||
sub r6.microcredits r1 into r7;
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Get the bond state for the validator, or fail if it does not exist.
|
||||
get bonded[r0] into r8;
|
||||
// Ensure that the validator matches in the bond state.
|
||||
assert.eq r8.validator r0;
|
||||
// Decrement the microcredits in the bond state.
|
||||
sub r8.microcredits r1 into r9;
|
||||
|
||||
// Determine if the remaining bond is at least one million credits.
|
||||
gte r9 1_000_000_000_000u64 into r10;
|
||||
|
||||
// If the remaining balance is at least 1 million credits, jump to the `decrement_validator` logic.
|
||||
branch.eq r10 true to decrement_validator;
|
||||
// If the remaining balance is less than 1 million credits, jump to the `remove_validator` logic.
|
||||
branch.eq r10 false to remove_validator;
|
||||
|
||||
/*** Decrement Validator ***/
|
||||
|
||||
// Starts the `decrement_validator` logic.
|
||||
position decrement_validator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Construct the updated committee state.
|
||||
cast r7 r6.is_open into r11 as committee_state;
|
||||
// Update the committee state for the validator.
|
||||
set r11 into committee[r0];
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Construct the updated bond state.
|
||||
cast r0 r9 into r12 as bond_state;
|
||||
// Update the bond state for the validator.
|
||||
set r12 into bonded[r0];
|
||||
|
||||
/* Unbonding */
|
||||
|
||||
// Increment the microcredits in the unbond state.
|
||||
add r3.microcredits r1 into r13;
|
||||
|
||||
// Construct the updated unbond state.
|
||||
cast r13 r4 into r14 as unbond_state;
|
||||
// Update the unbond state for the caller.
|
||||
set r14 into unbonding[r0];
|
||||
|
||||
// Ends the `decrement_validator` logic.
|
||||
branch.eq true true to end;
|
||||
|
||||
/*** Remove Validator ***/
|
||||
|
||||
// Starts the `remove_validator` logic.
|
||||
position remove_validator;
|
||||
|
||||
// Ensure that the validator has no delegators.
|
||||
assert.eq r6.microcredits r8.microcredits;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Remove the validator from the committee.
|
||||
remove committee[r0];
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Remove the bond state for the validator.
|
||||
remove bonded[r0];
|
||||
|
||||
/* Unbonding */
|
||||
|
||||
// Increment the microcredits in the unbond state.
|
||||
add r3.microcredits r8.microcredits into r15;
|
||||
|
||||
// Construct the updated unbond state.
|
||||
cast r15 r4 into r16 as unbond_state;
|
||||
// Update the unbond state for the caller.
|
||||
set r16 into unbonding[r0];
|
||||
|
||||
// Ends the `remove_validator` logic.
|
||||
branch.eq true true to end;
|
||||
|
||||
/******* Unbond Delegator *******/
|
||||
|
||||
// Starts the `unbond_delegator` logic.
|
||||
position unbond_delegator;
|
||||
|
||||
// Get the bond state for the caller, or fail if it does not exist.
|
||||
get bonded[r0] into r17;
|
||||
// Decrement the microcredits in the bond state.
|
||||
sub r17.microcredits r1 into r18;
|
||||
|
||||
// Determine if the remaining bond is at least 10 credits.
|
||||
gte r18 10_000_000u64 into r19;
|
||||
|
||||
// If the remaining balance is at least 10 credits, jump to the `decrement_delegator` logic.
|
||||
branch.eq r19 true to decrement_delegator;
|
||||
// If the remaining balance is less than 10 credits, jump to the `remove_delegator` logic.
|
||||
branch.eq r19 false to remove_delegator;
|
||||
|
||||
/*** Decrement Delegator ***/
|
||||
|
||||
// Starts the `decrement_delegator` logic.
|
||||
position decrement_delegator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Get the stake for the specified validator.
|
||||
// If the validator does not exist, this finalize scope will fail.
|
||||
get committee[r17.validator] into r20;
|
||||
// Decrement the stake for the specified validator.
|
||||
sub r20.microcredits r1 into r21;
|
||||
// Construct the updated committee state.
|
||||
cast r21 r20.is_open into r22 as committee_state;
|
||||
// Update the stake for the specified validator.
|
||||
set r22 into committee[r17.validator];
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Construct the updated bond state.
|
||||
cast r17.validator r18 into r23 as bond_state;
|
||||
// Update the bond state for the caller.
|
||||
set r23 into bonded[r0];
|
||||
|
||||
/* Unbonding */
|
||||
|
||||
// Increment the microcredits in the unbond state.
|
||||
add r3.microcredits r1 into r24;
|
||||
|
||||
// Construct the updated unbond state.
|
||||
cast r24 r4 into r25 as unbond_state;
|
||||
// Update the unbond state for the caller.
|
||||
set r25 into unbonding[r0];
|
||||
|
||||
// Ends the `decrement_delegator` logic.
|
||||
branch.eq true true to end;
|
||||
|
||||
/*** Remove Delegator ***/
|
||||
|
||||
// Starts the `remove_delegator` logic.
|
||||
position remove_delegator;
|
||||
|
||||
/* Committee */
|
||||
|
||||
// Get the stake for the specified validator.
|
||||
// If the validator does not exist, this finalize scope will fail.
|
||||
get committee[r17.validator] into r26;
|
||||
// Decrement the stake for the specified validator.
|
||||
sub r26.microcredits r17.microcredits into r27;
|
||||
// Construct the updated committee state.
|
||||
cast r27 r26.is_open into r28 as committee_state;
|
||||
// Update the stake for the specified validator.
|
||||
set r28 into committee[r17.validator];
|
||||
|
||||
/* Bonded */
|
||||
|
||||
// Remove the caller from the bonded mapping.
|
||||
remove bonded[r0];
|
||||
|
||||
/* Unbonding */
|
||||
|
||||
// Increment the microcredits in the unbond state.
|
||||
add r3.microcredits r17.microcredits into r29;
|
||||
|
||||
// Construct the updated unbond state.
|
||||
cast r29 r4 into r30 as unbond_state;
|
||||
// Update the unbond state for the caller.
|
||||
set r30 into unbonding[r0];
|
||||
|
||||
// The terminus.
|
||||
position end;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// This function allows a validator to unbond any delegator that is bonded to them.
|
||||
function unbond_delegator_as_validator:
|
||||
// Input the delegator's address.
|
||||
input r0 as address.public;
|
||||
|
||||
// Unbond the delegator as the validator.
|
||||
async unbond_delegator_as_validator self.caller r0 into r1;
|
||||
// Output the finalize future.
|
||||
output r1 as credits.aleo/unbond_delegator_as_validator.future;
|
||||
|
||||
finalize unbond_delegator_as_validator:
|
||||
// Input the validator's address.
|
||||
input r0 as address.public;
|
||||
// Input the delegator's address.
|
||||
input r1 as address.public;
|
||||
|
||||
/* Start Committee */
|
||||
|
||||
// Get the committee state for the specified validator.
|
||||
// If the validator does not exist, this finalize scope will fail.
|
||||
get committee[r0] into r2;
|
||||
// Enforce that the validator is closed to stakers.
|
||||
assert.eq r2.is_open false;
|
||||
|
||||
// Check if the delegator is a validator.
|
||||
contains committee[r1] into r3;
|
||||
// Enforce the delegator is *not* a validator.
|
||||
assert.eq r3 false;
|
||||
|
||||
/* End Committee */
|
||||
|
||||
/* Start Bonded */
|
||||
|
||||
// Get the bond state for the delegator, or fail if it does not exist.
|
||||
get bonded[r1] into r4;
|
||||
// Enforce that the delegator is bonded to the validator.
|
||||
assert.eq r4.validator r0;
|
||||
|
||||
/* End Bonded */
|
||||
|
||||
/* Start Committee */
|
||||
|
||||
// Decrement the stake for the specified validator.
|
||||
sub r2.microcredits r4.microcredits into r5;
|
||||
// Construct the updated committee state.
|
||||
cast r5 r2.is_open into r6 as committee_state;
|
||||
|
||||
/* End Committee */
|
||||
|
||||
/* Start Unbond */
|
||||
|
||||
// Construct the initial unbond state.
|
||||
cast 0u64 0u32 into r7 as unbond_state;
|
||||
// Get the unbond state for the delegator, or default to the initial unbond state.
|
||||
get.or_use unbonding[r1] r7 into r8;
|
||||
|
||||
// Increment the microcredits in the unbond state.
|
||||
add r8.microcredits r4.microcredits into r9;
|
||||
// Compute the height at which the unbonding will be complete, starting from the current block.
|
||||
// Note: Calling unbond across multiple blocks before the unbonding is complete will reset the height each time.
|
||||
add block.height 360u32 into r10;
|
||||
|
||||
// Construct the updated unbond state.
|
||||
cast r9 r10 into r11 as unbond_state;
|
||||
|
||||
/* End Unbond */
|
||||
|
||||
/* Start Writes */
|
||||
|
||||
// Update the committee state for the specified validator.
|
||||
set r6 into committee[r0];
|
||||
// Remove the bond state for the delegator.
|
||||
remove bonded[r1];
|
||||
// Update the unbond state for the delegator.
|
||||
set r11 into unbonding[r1];
|
||||
|
||||
/* End Writes */
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// This function allows any staker to claim their microcredits after the unbonding period.
|
||||
function claim_unbond_public:
|
||||
// Claim the unbonded microcredits.
|
||||
async claim_unbond_public self.caller into r0;
|
||||
// Output the finalize future.
|
||||
output r0 as credits.aleo/claim_unbond_public.future;
|
||||
|
||||
finalize claim_unbond_public:
|
||||
// Input the staker's address.
|
||||
input r0 as address.public;
|
||||
|
||||
// Get the unbond state for the caller, or fail if it does not exist.
|
||||
get unbonding[r0] into r1;
|
||||
// Determine if unbonding is complete.
|
||||
gte block.height r1.height into r2;
|
||||
// Enforce the unbonding is complete.
|
||||
assert.eq r2 true;
|
||||
|
||||
// Add the unbonded amount to the stakers's public balance.
|
||||
// Increments `account[r0]` by `r1`.
|
||||
// If `account[r0]` does not exist, 0u64 is used.
|
||||
// If `account[r0] + r2` overflows, `claim_unbond_public` is reverted.
|
||||
get.or_use account[r0] 0u64 into r3;
|
||||
add r1.microcredits r3 into r4;
|
||||
set r4 into account[r0];
|
||||
|
||||
// Remove the unbond state for the caller.
|
||||
remove unbonding[r0];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// This function allows a validator to set their state to be either opened or closed to stakers.
|
||||
// When the validator is open to stakers, any staker (including the validator) can bond or unbond from the validator.
|
||||
// When the validator is closed to stakers, all stakers can only unbond from the validator.
|
||||
//
|
||||
// This function serves two primary purposes:
|
||||
// 1. Allow a validator to leave the committee, by closing themselves to stakers and then unbonding all of their stakers.
|
||||
// 2. Allow a validator to maintain their % of stake, by closing themselves to allowing more stakers to bond to them.
|
||||
function set_validator_state:
|
||||
// Input the 'is_open' state.
|
||||
input r0 as boolean.public;
|
||||
// Set the validator to be either open or closed to stakers.
|
||||
async set_validator_state self.caller r0 into r1;
|
||||
// Output the finalize future.
|
||||
output r1 as credits.aleo/set_validator_state.future;
|
||||
|
||||
finalize set_validator_state:
|
||||
// Input the validator's address.
|
||||
input r0 as address.public;
|
||||
// Input the 'is_open' state.
|
||||
input r1 as boolean.public;
|
||||
|
||||
// Get the committee state for the specified validator.
|
||||
// If the validator does not exist, this finalize scope will fail.
|
||||
get committee[r0] into r2;
|
||||
|
||||
// Construct the updated committee state.
|
||||
cast r2.microcredits r1 into r3 as committee_state;
|
||||
// Update the committee state for the specified validator.
|
||||
set r3 into committee[r0];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `transfer_public` function sends the specified amount
|
||||
// from the sender's `account` to the receiver's `account`.
|
||||
function transfer_public:
|
||||
// Input the receiver.
|
||||
input r0 as address.public;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Transfer the credits publicly.
|
||||
async transfer_public self.caller r0 r1 into r2;
|
||||
// Output the finalize future.
|
||||
output r2 as credits.aleo/transfer_public.future;
|
||||
|
||||
finalize transfer_public:
|
||||
// Input the sender.
|
||||
input r0 as address.public;
|
||||
// Input the receiver.
|
||||
input r1 as address.public;
|
||||
// Input the amount.
|
||||
input r2 as u64.public;
|
||||
// Decrements `account[r0]` by `r2`.
|
||||
// If `account[r0]` does not exist, 0u64 is used.
|
||||
// If `account[r0] - r2` underflows, `transfer_public` is reverted.
|
||||
get.or_use account[r0] 0u64 into r3;
|
||||
sub r3 r2 into r4;
|
||||
set r4 into account[r0];
|
||||
// Increments `account[r1]` by `r2`.
|
||||
// If `account[r1]` does not exist, 0u64 is used.
|
||||
// If `account[r1] + r2` overflows, `transfer_public` is reverted.
|
||||
get.or_use account[r1] 0u64 into r5;
|
||||
add r5 r2 into r6;
|
||||
set r6 into account[r1];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `transfer_private` function sends the specified amount
|
||||
// from the sender's record to the receiver in a record.
|
||||
function transfer_private:
|
||||
// Input the sender's record.
|
||||
input r0 as credits.record;
|
||||
// Input the receiver.
|
||||
input r1 as address.private;
|
||||
// Input the amount.
|
||||
input r2 as u64.private;
|
||||
// Checks the given record has a sufficient amount.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an underflow occurs. The destination register `r3` holds
|
||||
// the change amount to be returned to the sender.
|
||||
sub r0.microcredits r2 into r3;
|
||||
// Construct a record for the specified receiver.
|
||||
cast r1 r2 into r4 as credits.record;
|
||||
// Construct a record with the change amount for the sender.
|
||||
cast r0.owner r3 into r5 as credits.record;
|
||||
// Output the receiver's record.
|
||||
output r4 as credits.record;
|
||||
// Output the sender's change record.
|
||||
output r5 as credits.record;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `transfer_private_to_public` function turns a specified amount
|
||||
// from a record into public credits for the specified receiver.
|
||||
//
|
||||
// This function preserves privacy for the sender's record, however
|
||||
// it publicly reveals the receiver and the amount.
|
||||
function transfer_private_to_public:
|
||||
// Input the sender's record.
|
||||
input r0 as credits.record;
|
||||
// Input the receiver.
|
||||
input r1 as address.public;
|
||||
// Input the amount.
|
||||
input r2 as u64.public;
|
||||
// Checks the given record has a sufficient amount.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an underflow occurs. The destination register `r3` holds
|
||||
// the change amount for the sender.
|
||||
sub r0.microcredits r2 into r3;
|
||||
// Construct a record with the change amount for the sender.
|
||||
cast r0.owner r3 into r4 as credits.record;
|
||||
// Increment the amount publicly for the receiver.
|
||||
async transfer_private_to_public r1 r2 into r5;
|
||||
// Output the sender's change record.
|
||||
output r4 as credits.record;
|
||||
// Output the finalize future.
|
||||
output r5 as credits.aleo/transfer_private_to_public.future;
|
||||
|
||||
finalize transfer_private_to_public:
|
||||
// Input the receiver.
|
||||
input r0 as address.public;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Retrieve the balance of the sender.
|
||||
// If `account[r0]` does not exist, 0u64 is used.
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
// Increments `account[r0]` by `r1`.
|
||||
// If `r1 + r2` overflows, `transfer_private_to_public` is reverted.
|
||||
add r1 r2 into r3;
|
||||
// Updates the balance of the sender.
|
||||
set r3 into account[r0];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `transfer_public_to_private` function turns a specified amount
|
||||
// from the mapping `account` into a record for the specified receiver.
|
||||
//
|
||||
// This function publicly reveals the sender, the receiver, and the specified amount.
|
||||
// However, subsequent methods using the receiver's record can preserve the receiver's privacy.
|
||||
function transfer_public_to_private:
|
||||
// Input the receiver.
|
||||
input r0 as address.private;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Construct a record for the receiver.
|
||||
cast r0 r1 into r2 as credits.record;
|
||||
// Decrement the balance of the sender publicly.
|
||||
async transfer_public_to_private self.caller r1 into r3;
|
||||
// Output the record of the receiver.
|
||||
output r2 as credits.record;
|
||||
// Output the finalize future.
|
||||
output r3 as credits.aleo/transfer_public_to_private.future;
|
||||
|
||||
finalize transfer_public_to_private:
|
||||
// Input the sender.
|
||||
input r0 as address.public;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Retrieve the balance of the sender.
|
||||
// If `account[r0]` does not exist, 0u64 is used.
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
// Decrements `account[r0]` by `r1`.
|
||||
// If `r2 - r1` underflows, `transfer_public_to_private` is reverted.
|
||||
sub r2 r1 into r3;
|
||||
// Updates the balance of the sender.
|
||||
set r3 into account[r0];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `join` function combines two records into one.
|
||||
function join:
|
||||
// Input the first record.
|
||||
input r0 as credits.record;
|
||||
// Input the second record.
|
||||
input r1 as credits.record;
|
||||
// Combines the amount of the first record and the second record.
|
||||
// This `add` operation is safe, and the proof will fail
|
||||
// if an overflow occurs.
|
||||
add r0.microcredits r1.microcredits into r2;
|
||||
// Construct a record with the combined amount.
|
||||
cast r0.owner r2 into r3 as credits.record;
|
||||
// Output the record.
|
||||
output r3 as credits.record;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `split` function splits a record into two records. The given input amount will be stored in the first record,
|
||||
// and the remaining amount will be stored in the second record, with the fee deducted from the remaining amount.
|
||||
// If the caller executes a transaction that contains only a call to this function, then the transaction does not
|
||||
// require a fee, unless the caller wishes to provide an additional fee. Transactions that contain multiple transitions
|
||||
// (that include one or more calls to this function) will require a fee as per standard consensus rules.
|
||||
function split:
|
||||
// Input the record.
|
||||
input r0 as credits.record;
|
||||
// Input the amount to split.
|
||||
input r1 as u64.private;
|
||||
// Checks the given record has a sufficient amount to split.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an underflow occurs.
|
||||
sub r0.microcredits r1 into r2;
|
||||
// Checks the given record has a sufficient fee to remove.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an underflow occurs.
|
||||
sub r2 10_000u64 into r3;
|
||||
// Construct the first record.
|
||||
cast r0.owner r1 into r4 as credits.record;
|
||||
// Construct the second record.
|
||||
cast r0.owner r3 into r5 as credits.record;
|
||||
// Output the first record.
|
||||
output r4 as credits.record;
|
||||
// Output the second record.
|
||||
output r5 as credits.record;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `fee_private` function charges the specified amount from the sender's record.
|
||||
function fee_private:
|
||||
// Input the sender's record.
|
||||
input r0 as credits.record;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Input the deployment or execution root.
|
||||
input r2 as field.public;
|
||||
// Ensure the amount is nonzero.
|
||||
assert.neq r1 0u64;
|
||||
// Ensure the deployment or execution root is nonzero.
|
||||
assert.neq r2 0field;
|
||||
// Checks the given record has a sufficient amount.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an underflow occurs. The destination register `r3` holds
|
||||
// the change amount for the sender.
|
||||
sub r0.microcredits r1 into r3;
|
||||
// Construct a record with the change amount for the sender.
|
||||
cast r0.owner r3 into r4 as credits.record;
|
||||
// Output the sender's change record.
|
||||
output r4 as credits.record;
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// The `fee_public` function charges the specified amount from the sender's account.
|
||||
function fee_public:
|
||||
// Input the amount.
|
||||
input r0 as u64.public;
|
||||
// Input the deployment or execution root.
|
||||
input r1 as field.public;
|
||||
// Ensure the amount is nonzero.
|
||||
assert.neq r0 0u64;
|
||||
// Ensure the deployment or execution root is nonzero.
|
||||
assert.neq r1 0field;
|
||||
// Decrement the balance of the sender publicly.
|
||||
async fee_public self.caller r0 into r2;
|
||||
// Output the finalize future.
|
||||
output r2 as credits.aleo/fee_public.future;
|
||||
|
||||
finalize fee_public:
|
||||
// Input the sender's address.
|
||||
input r0 as address.public;
|
||||
// Input the amount.
|
||||
input r1 as u64.public;
|
||||
// Retrieve the balance of the sender.
|
||||
// If `account[r0]` does not exist, `fee_public` is reverted.
|
||||
get account[r0] into r2;
|
||||
// Decrements `account[r0]` by `r1`.
|
||||
// If `r2 - r1` underflows, `fee_public` is reverted.
|
||||
sub r2 r1 into r3;
|
||||
// Updates the balance of the sender.
|
||||
set r3 into account[r0];
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
// Open Questions:
|
||||
// fn bond
|
||||
// - if the bond is now 33% or more, close the validator. (determine how hard to impl this)
|
||||
|
||||
/**********************************************************************************************************************/
|
242
utils/disassembler/src/tests/large_functions.aleo
Normal file
242
utils/disassembler/src/tests/large_functions.aleo
Normal file
@ -0,0 +1,242 @@
|
||||
import credits.aleo;
|
||||
|
||||
program large_functions.aleo;
|
||||
|
||||
function join_3:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
call credits.aleo/join r0 r1 into r3;
|
||||
call credits.aleo/join r3 r2 into r4;
|
||||
output r4 as credits.aleo/credits.record;
|
||||
|
||||
function join_5:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
call credits.aleo/join r0 r1 into r5;
|
||||
call credits.aleo/join r2 r3 into r6;
|
||||
call credits.aleo/join r5 r6 into r7;
|
||||
call credits.aleo/join r7 r4 into r8;
|
||||
output r8 as credits.aleo/credits.record;
|
||||
|
||||
function join6:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
call credits.aleo/join r0 r1 into r6;
|
||||
call credits.aleo/join r2 r3 into r7;
|
||||
call credits.aleo/join r4 r5 into r8;
|
||||
call credits.aleo/join r6 r7 into r9;
|
||||
call credits.aleo/join r9 r8 into r10;
|
||||
output r10 as credits.aleo/credits.record;
|
||||
|
||||
function join7:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
input r6 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
assert.eq r5.owner r6.owner;
|
||||
call credits.aleo/join r0 r1 into r7;
|
||||
call credits.aleo/join r2 r3 into r8;
|
||||
call credits.aleo/join r4 r5 into r9;
|
||||
call credits.aleo/join r7 r8 into r10;
|
||||
call credits.aleo/join r10 r9 into r11;
|
||||
call credits.aleo/join r11 r6 into r12;
|
||||
output r12 as credits.aleo/credits.record;
|
||||
|
||||
function join8:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
input r6 as credits.aleo/credits.record;
|
||||
input r7 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
assert.eq r5.owner r6.owner;
|
||||
assert.eq r6.owner r7.owner;
|
||||
call credits.aleo/join r0 r1 into r8;
|
||||
call credits.aleo/join r2 r3 into r9;
|
||||
call credits.aleo/join r4 r5 into r10;
|
||||
call credits.aleo/join r6 r7 into r11;
|
||||
call credits.aleo/join r8 r9 into r12;
|
||||
call credits.aleo/join r11 r10 into r13;
|
||||
call credits.aleo/join r12 r13 into r14;
|
||||
output r14 as credits.aleo/credits.record;
|
||||
|
||||
function join9:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
input r6 as credits.aleo/credits.record;
|
||||
input r7 as credits.aleo/credits.record;
|
||||
input r8 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
assert.eq r5.owner r6.owner;
|
||||
assert.eq r6.owner r7.owner;
|
||||
assert.eq r7.owner r8.owner;
|
||||
call credits.aleo/join r0 r1 into r9;
|
||||
call credits.aleo/join r2 r3 into r10;
|
||||
call credits.aleo/join r4 r5 into r11;
|
||||
call credits.aleo/join r6 r7 into r12;
|
||||
call credits.aleo/join r9 r10 into r13;
|
||||
call credits.aleo/join r12 r11 into r14;
|
||||
call credits.aleo/join r13 r14 into r15;
|
||||
call credits.aleo/join r15 r8 into r16;
|
||||
output r16 as credits.aleo/credits.record;
|
||||
|
||||
function join10:
|
||||
input r0 as credits.aleo/credits.record;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
input r6 as credits.aleo/credits.record;
|
||||
input r7 as credits.aleo/credits.record;
|
||||
input r8 as credits.aleo/credits.record;
|
||||
input r9 as credits.aleo/credits.record;
|
||||
assert.eq r0.owner r1.owner;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
assert.eq r5.owner r6.owner;
|
||||
assert.eq r6.owner r7.owner;
|
||||
assert.eq r7.owner r8.owner;
|
||||
assert.eq r8.owner r9.owner;
|
||||
call credits.aleo/join r0 r1 into r10;
|
||||
call credits.aleo/join r2 r3 into r11;
|
||||
call credits.aleo/join r4 r5 into r12;
|
||||
call credits.aleo/join r6 r7 into r13;
|
||||
call credits.aleo/join r8 r9 into r14;
|
||||
call credits.aleo/join r10 r11 into r15;
|
||||
call credits.aleo/join r13 r12 into r16;
|
||||
call credits.aleo/join r15 r16 into r17;
|
||||
call credits.aleo/join r17 r14 into r18;
|
||||
output r18 as credits.aleo/credits.record;
|
||||
|
||||
function transfer_3:
|
||||
input r0 as address.private;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
call credits.aleo/transfer_private r1 r0 r1.microcredits into r4 r5;
|
||||
call credits.aleo/transfer_private r2 r0 r2.microcredits into r6 r7;
|
||||
call credits.aleo/transfer_private r3 r0 r3.microcredits into r8 r9;
|
||||
output r4 as credits.aleo/credits.record;
|
||||
output r5 as credits.aleo/credits.record;
|
||||
output r6 as credits.aleo/credits.record;
|
||||
output r7 as credits.aleo/credits.record;
|
||||
output r8 as credits.aleo/credits.record;
|
||||
output r9 as credits.aleo/credits.record;
|
||||
|
||||
function transfer_5:
|
||||
input r0 as address.private;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
call credits.aleo/transfer_private r1 r0 r1.microcredits into r6 r7;
|
||||
call credits.aleo/transfer_private r2 r0 r2.microcredits into r8 r9;
|
||||
call credits.aleo/transfer_private r3 r0 r3.microcredits into r10 r11;
|
||||
call credits.aleo/transfer_private r4 r0 r4.microcredits into r12 r13;
|
||||
call credits.aleo/transfer_private r5 r0 r5.microcredits into r14 r15;
|
||||
output r6 as credits.aleo/credits.record;
|
||||
output r7 as credits.aleo/credits.record;
|
||||
output r8 as credits.aleo/credits.record;
|
||||
output r9 as credits.aleo/credits.record;
|
||||
output r10 as credits.aleo/credits.record;
|
||||
output r11 as credits.aleo/credits.record;
|
||||
output r12 as credits.aleo/credits.record;
|
||||
output r13 as credits.aleo/credits.record;
|
||||
output r14 as credits.aleo/credits.record;
|
||||
output r15 as credits.aleo/credits.record;
|
||||
|
||||
function split_3:
|
||||
input r0 as u64.private;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
call credits.aleo/split r1 r0 into r4 r5;
|
||||
call credits.aleo/split r2 r0 into r6 r7;
|
||||
call credits.aleo/split r3 r0 into r8 r9;
|
||||
output r4 as credits.aleo/credits.record;
|
||||
output r5 as credits.aleo/credits.record;
|
||||
output r6 as credits.aleo/credits.record;
|
||||
output r7 as credits.aleo/credits.record;
|
||||
output r8 as credits.aleo/credits.record;
|
||||
output r9 as credits.aleo/credits.record;
|
||||
|
||||
function split_5:
|
||||
input r0 as u64.private;
|
||||
input r1 as credits.aleo/credits.record;
|
||||
input r2 as credits.aleo/credits.record;
|
||||
input r3 as credits.aleo/credits.record;
|
||||
input r4 as credits.aleo/credits.record;
|
||||
input r5 as credits.aleo/credits.record;
|
||||
assert.eq r1.owner r2.owner;
|
||||
assert.eq r2.owner r3.owner;
|
||||
assert.eq r3.owner r4.owner;
|
||||
assert.eq r4.owner r5.owner;
|
||||
call credits.aleo/split r1 r0 into r6 r7;
|
||||
call credits.aleo/split r2 r0 into r8 r9;
|
||||
call credits.aleo/split r3 r0 into r10 r11;
|
||||
call credits.aleo/split r4 r0 into r12 r13;
|
||||
call credits.aleo/split r5 r0 into r14 r15;
|
||||
output r6 as credits.aleo/credits.record;
|
||||
output r7 as credits.aleo/credits.record;
|
||||
output r8 as credits.aleo/credits.record;
|
||||
output r9 as credits.aleo/credits.record;
|
||||
output r10 as credits.aleo/credits.record;
|
||||
output r11 as credits.aleo/credits.record;
|
||||
output r12 as credits.aleo/credits.record;
|
||||
output r13 as credits.aleo/credits.record;
|
||||
output r14 as credits.aleo/credits.record;
|
||||
output r15 as credits.aleo/credits.record;
|
Loading…
Reference in New Issue
Block a user