Calling a second contract from within a NEAR contract (rust) - rust

On NEARprotocol, I want to call another contract from within a contract (Rust).
I tried env::Promise but could not retrieve the call answer. What is the right approach here? Also, the near-sdk crate docs give the example &"bob_near".to_string(), is that equivalent to the id bob.near or a typo?
Here are the relevant excerpts of my code:
near_sdk::setup_alloc!();
#[ext_contract]
pub trait AEXToken {
fn collect_premie(&mut self, account_id: ValidAccountId) -> bool;
fn get_min_balance(&self) -> u128;
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
tokens: NonFungibleToken,
metadata: LazyOption<NFTContractMetadata>,
aex_tokenId: ValidAccountId,
}
#[near_bindgen]
impl Contract {
pub fn nft_mint(&mut self) -> Token {
let amount: Balance = env::attached_deposit();
aex_token::get_min_balance(&self.aex_tokenId.to_string(), 0, 1_000);
let min_balance: u128 = env::promise_return(1);
assert!(min_balance < amount);

I think you're misunderstanding the way this works. the promise does not return in this same method. it's executed in some subsequent block, as soon as possible depending on network congestion, usually within 1 block.
The return value will land in another method as a callback. See this example and several others in the same examples folder with the SDK
calling out
/// Call functions a, b, and c asynchronously and handle results with `handle_callbacks`.
pub fn call_all(fail_b: bool, c_value: u8) -> Promise {
let gas_per_promise = env::prepaid_gas() / 5;
ext::a(env::current_account_id(), 0, gas_per_promise)
.and(ext::b(fail_b, env::current_account_id(), 0, gas_per_promise))
.and(ext::c(c_value, env::current_account_id(), 0, gas_per_promise))
.then(ext::handle_callbacks(env::current_account_id(), 0, gas_per_promise))
}
receiving callback
/// Receives the callbacks from the other promises called.
#[private]
pub fn handle_callbacks(
#[callback_unwrap] a: u8,
#[callback_result] b: Result<String, PromiseError>,
#[callback_result] c: Result<u8, PromiseError>,
) -> (bool, bool) {
require!(a == A_VALUE, "Promise returned incorrect value");
if let Ok(s) = b.as_ref() {
require!(s == "Some string");
}
(b.is_err(), c.is_err())
}
and this might help with a little more explanation around it
https://www.near-sdk.io/cross-contract/callbacks
so your call out
aex_token::get_min_balance(&self.aex_tokenId.to_string(), 0, 1_000);
should be chained using then to a callback where you execute this check
let min_balance: u128 = env::promise_return(1);
assert!(min_balance < amount);

Related

Looking for a better design pattern for methods of enums in Rust

I need a way to put different objects that all implement a certain trait integrate() in one enum. This enum shall implement a method that calls its variant's method integrate() in a certain way e.g. many times.
I tried to make a very simple example, but it is still not as short as I would want it to be.
Some more explanation: I want to write a solver that integrates certain differential equations i.e. calculate how a physical system behaves over a certain time span. For each time step the method integrate() is called. But when I execute the program I want to be able to choose which physical system is used at runtime. My idea was to have an enum that has the different physical systems in it e.g. OscillatorA and OscillatorB (in reality this could be a double pendulum, or a vibrating string - doesn't matter).
pub trait Integrate {
fn integrate(&mut self);
}
pub struct OscillatorA {
z: u32,
}
impl Integrate for OscillatorA {
fn integrate(&mut self) {
self.z += 1; // something happens here
}
}
#[derive(Debug)]
pub struct OscillatorB {
x: u32,
y: u32,
}
impl Integrate for OscillatorB {
fn integrate(&mut self) {
self.x += 1; // something different happens here
self.y += 2;
}
}
#[derive(Debug)]
pub enum Oscillator {
A(OscillatorA),
B(OscillatorB),
// ... many other physical systems come here
}
impl Oscillator {
pub fn new(num: &u64) -> Self {
match num {
0 => Self::A(OscillatorA { z: 1 }),
1.. => Self::B(OscillatorB { x: 1, y: 2 }),
}
}
}
impl Integrate for Oscillator {
fn integrate(&mut self) {
// this looks like it should be redundant:
match self {
Self::A(osc) => osc.integrate(),
Self::B(osc) => osc.integrate(),
}
}
}
pub fn integrate_n_times(object: &mut impl Integrate, n: u64) {
for _ in 0..n {
object.integrate();
}
}
fn main() {
let which = 0; // can be set via commandline arguments.
let mut s = Oscillator::new(&which);
integrate_n_times(&mut s, 10);
// ..
}
The function integrate_n_times(&mut self, n) will call n times the integrate() method required by the Integrate-trait. But it somehow doesn't feel right, because it will at each iteration solve a match-statement. I guess with compiler optimizations this might be avoided, but it somehow "feels" wrong, because it certainly reads like this.
Is there a better design pattern I am missing? Should I require the method "integrate_n_times" through the trait as well? (But then I would rely on it being written correctly in every Oscillator struct).
I somehow need to have one "main-struct" that I contains all the different physical systems and can call them depending on what arguments I pass to the program.
I would probably use dynamic dispatch here. While it's generally slower than using static dispatch, I would imagine it's faster than a massive match cases. Plus I think it's easier to work with, as long as we don't try to get the original type with Any and down-casting.
impl Oscillator {
pub fn new(num: &u64) -> Box<dyn Integrate> {
match num {
0 => Box::new(OscillatorA { z: 1 }),
1.. => Box::new(OscillatorB { x: 1, y: 2 }),
}
}
}
pub fn integrate_n_times(object: &mut Box<dyn Integrate>, n: u64) {
for _ in 0..n {
object.integrate();
}
}
fn main() {
let which = 0; // can be set via commandline arguments.
let mut my_oscillator: Box<dyn Integrate> = Oscillator::new(&which);
integrate_n_times(&mut my_oscillator, 10);
}

Derive macro generation

I'm making my own Serializable trait, in the context of a client / server system.
My idea was that the messages sent by the system is an enum made by the user of this system, so it can be customize as needed.
Too ease implementing the trait on the enum, I would like to use the #[derive(Serializable)] method, as implementing it is always the same thing.
Here is the trait :
pub trait NetworkSerializable {
fn id(&self) -> usize;
fn size(&self) -> usize;
fn serialize(self) -> Vec<u8>;
fn deserialize(id: usize, data: Vec<u8>) -> Self;
}
Now, I've tried to look at the book (this one too) and this example to try to wrap my head around derive macros, but I'm really struggling to understand them and how to implement them. I've read about token streams and abstract trees, and I think I understand the basics.
Let's take the example of the id() method : it should gives a unique id for each variant of the enum, to allow headers of messages to tell which message is incoming.
let's say I have this enum as a message system :
enum NetworkMessages {
ErrorMessage,
SpawnPlayer(usize, bool, Transform), // player id, is_mine, position
MovePlayer(usize, Transform), // player id, new_position
DestroyPlayer(usize) // player_id
}
Then, the id() function should look like this :
fn id(&self) -> usize {
match &self {
&ErrorMessage => 0,
&SpawnPlayer => 1,
&MovePlayer => 2,
&DestroyPlayer => 3,
}
}
Here was my go with writting this using a derive macro :
#[proc_macro_derive(NetworkSerializable)]
pub fn network_serializable_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_network_serializable_macro(&ast)
}
fn impl_network_serializable_macro(ast: &syn::DeriveInput) -> TokenStream {
// get enum name
let ref name = ast.ident;
let ref data = ast.data;
let (id_func, size_func, serialize_func, deserialize_func) = match data {
// Only if data is an enum, we do parsing
Data::Enum(data_enum) => {
// Iterate over enum variants
let mut id_func_internal = TokenStream2::new();
let mut variant_id: usize = 0;
for variant in &data_enum.variants {
// add the branch for the variant
id_func_internal.extend(quote_spanned!{
variant.span() => &variant_id,
});
variant_id += 1;
}
(id_func_internal, (), (), ())
}
_ => {(TokenStream2::new(), (), (), ())},
};
let expanded = quote! {
impl NetworkSerializable for #name {
// variant_checker_functions gets replaced by all the functions
// that were constructed above
fn size(&self) -> usize {
match &self {
#id_func
}
}
/*
#size_func
#serialize_func
#deserialize_func
*/
}
};
expanded.into()
}
So this is generating quite a lot of errors, with the "proc macro NetworkSerializable not expanded: no proc macro dylib present" being first. So I'm guessing there a lot of misunderstaning from my part in here.

How to implement callback on typing in textbox with rust druid (not lens, but a method call)?

I want to call the following method with arguments, either by passing them or from a closure:
fn set_border(&mut self, arg: &str, is_left_border: bool) -> () {
let val = arg.parse::<f64>();
match val {
Ok(float) => { if is_left_border {self.left_border = Some(float)} else {self.right_border = Some(float)}},
Err(_) => {}
}
}
when text is entered to the textbox. I didn't find a way to use lens to access methods, but I'm quite new to rust and decided to ask for advice.
As far as I'm concerned if I can "track" changes of the field and do it that way it will also do.
Thanks in advance.
You can use a Controller to be called when the TextBox receives a call to its update method and then check whether the data has changed:
use druid::{
AppLauncher,
WidgetExt,
Widget,
Env,
UpdateCtx,
WindowDesc,
widget::TextBox,
widget::Controller
};
struct UpdateCallback();
impl Controller<String, TextBox<String>> for UpdateCallback {
fn update(&mut self,
child: &mut TextBox<String>,
ctx: &mut UpdateCtx<'_, '_>,
old_data: &String,
data: &String,
env: &Env
) {
if old_data != data {
// the data has changed, you can call your function here
println!("{}", data);
}
// also inform the child that the data has changed
child.update(ctx, old_data, data, env)
}
}
fn build_root_widget() -> impl Widget<String> {
TextBox::new().controller(UpdateCallback())
}
fn main() {
AppLauncher::with_window(WindowDesc::new(build_root_widget)).launch("Test".to_string()).unwrap();
}
The relevant part here is the Controller impl for UpdateCallback as well as the call to controller() inside the build_root_widget() function.

How to access the value of a field in a tracing span?

I'm using the tracing library in my project and there is one thing I'm not able to figure out: How can I access a value (that I set in my span when I create it) in my Layer?
My layer looks like this:
impl<S> Layer<S> for CustomLayer where S: Subscriber {
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
Interest::sometimes() //hardcoding so enabled() will be called everytime a span is created
}
fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
if metadata.is_span() {
// How do I access value of key here?
if value == X {
true
} else if value == Y {
false
}
}
true // default
}
}
You can access the data in a Span if you have access to either its ValueSet (as found in new_span() or on_new_span() via Attributes) or a Record entry for it (as found in record() or on_record()). With that you can use the visitor pattern to find the information you desire. Here's a simple implementation that checks if a field exists and its value is a matching string:
use std::fmt::Debug;
use tracing::field::{ValueSet, Visit, Field};
use tracing::span::Record;
struct MatchStrVisitor<'a> {
field: &'a str,
value: &'a str,
matched: bool,
}
impl Visit for MatchStrVisitor<'_> {
fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == self.field && value == self.value {
self.matched = true;
}
}
}
fn value_in_valueset(valueset: &ValueSet<'_>, field: &str, value: &str) -> bool {
let mut visitor = MatchStrVisitor { field, value, matched: false };
valueset.record(&mut visitor);
visitor.matched
}
fn value_in_record(record: &Record<'_>, field: &str, value: &str) -> bool {
let mut visitor = MatchStrVisitor { field, value, matched: false };
record.record(&mut visitor);
visitor.matched
}
This is pretty rudimentary but hopefully demonstrates what is possible. One thing to note is that the "value" that is stored is either a primitive value (i64, u64, bool, str, etc.) or in a type-erased form via &dyn Debug. Those are the only types of values you can receive from the visitor.
Addressing OP's case in particular, as explained in this issue you cannot access this information in the enabled() method since that occurs before any values are recorded. You will need to make your determination in the new_span() method, and use span extensions via the registry to track whether you consider the span is "enabled" in your other methods.
Here's another rudimentary example:
use tracing::span::Attributes;
use tracing::{Subscriber, Metadata, Id, Event};
use tracing::subscriber::Interest;
use tracing_subscriber::layer::{Context, Layer};
use tracing_subscriber::registry::LookupSpan;
struct CustomLayer;
struct CustomLayerEnabled;
impl<S> Layer<S> for CustomLayer where S: Subscriber + for <'a> LookupSpan<'a> {
fn register_callsite(&self, _metadata: &'static Metadata<'static>) -> Interest {
Interest::sometimes()
}
fn enabled(&self, metadata: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {
metadata.is_span()
}
fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
if value_in_valueset(attrs.values(), "myfield", "myvalue") {
ctx.span(id).unwrap().extensions_mut().insert(CustomLayerEnabled);
}
}
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
let span_id = event.parent().unwrap();
if let None = ctx.span(span_id).unwrap().extensions().get::<CustomLayerEnabled>() {
return;
}
// ... rest of your logic
}
}
Note: I've completely rewritten this answer taking info from the comments and my newfound experience.

How to implement a long running process with progress in Rust, available via a Rest api?

I am a beginner in Rust.
I have a long running IO-bound process that I want to spawn and monitor via a REST API. I chose Iron for that, following this tutorial . Monitoring means getting its progress and its final result.
When I spawn it, I give it an id and map that id to a resource that I can GET to get the progress. I don't have to be exact with the progress; I can report the progress from 5 seconds ago.
My first attempt was to have a channel via which I send request for progress and receive the status. I got stuck where to store the receiver, as in my understanding it belongs to one thread only. I wanted to put it in the context of the request, but that won't work as there are different threads handling subsequent requests.
What would be the idiomatic way to do this in Rust?
I have a sample project.
Later edit:
Here is a self contained example which follows the sample principle as the answer, namely a map where each thread updates its progress:
extern crate iron;
extern crate router;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json;
use std::io::Read;
use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;
use std::collections::HashMap;
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub struct Status {
pub progress: u64,
pub context: String
}
#[derive(RustcEncodable, RustcDecodable)]
struct StartTask {
id: u64
}
fn start_process(status: Arc<Mutex<HashMap<u64, Status>>>, task_id: u64) {
let c = status.clone();
thread::spawn(move || {
for i in 1..100 {
{
let m = &mut c.lock().unwrap();
m.insert(task_id, Status{ progress: i, context: "in progress".to_string()});
}
thread::sleep(Duration::from_secs(1));
}
let m = &mut c.lock().unwrap();
m.insert(task_id, Status{ progress: 100, context: "done".to_string()});
});
}
fn main() {
let status: Arc<Mutex<HashMap<u64, Status>>> = Arc::new(Mutex::new(HashMap::new()));
let status_clone: Arc<Mutex<HashMap<u64, Status>>> = status.clone();
let mut router = Router::new();
router.get("/:taskId", move |r: &mut Request| task_status(r, &status.lock().unwrap()));
router.post("/start", move |r: &mut Request|
start_task(r, status_clone.clone()));
fn task_status(req: &mut Request, statuses: & HashMap<u64,Status>) -> IronResult<Response> {
let ref task_id = req.extensions.get::<Router>().unwrap().find("taskId").unwrap_or("/").parse::<u64>().unwrap();
let payload = json::encode(&statuses.get(&task_id)).unwrap();
Ok(Response::with((status::Ok, payload)))
}
// Receive a message by POST and play it back.
fn start_task(request: &mut Request, statuses: Arc<Mutex<HashMap<u64, Status>>>) -> IronResult<Response> {
let mut payload = String::new();
request.body.read_to_string(&mut payload).unwrap();
let task_start_request: StartTask = json::decode(&payload).unwrap();
start_process(statuses, task_start_request.id);
Ok(Response::with((status::Ok, json::encode(&task_start_request).unwrap())))
}
Iron::new(router).http("localhost:3000").unwrap();
}
One possibility is to use a global HashMap that associate each worker id with the progress (and result). Here is simple example (without the rest stuff)
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
use std::collections::HashMap;
use std::thread;
use std::time::Duration;
lazy_static! {
static ref PROGRESS: Mutex<HashMap<usize, usize>> = Mutex::new(HashMap::new());
}
fn set_progress(id: usize, progress: usize) {
// insert replaces the old value if there was one.
PROGRESS.lock().unwrap().insert(id, progress);
}
fn get_progress(id: usize) -> Option<usize> {
PROGRESS.lock().unwrap().get(&id).cloned()
}
fn work(id: usize) {
println!("Creating {}", id);
set_progress(id, 0);
for i in 0..100 {
set_progress(id, i + 1);
// simulates work
thread::sleep(Duration::new(0, 50_000_000));
}
}
fn monitor(id: usize) {
loop {
if let Some(p) = get_progress(id) {
if p == 100 {
println!("Done {}", id);
// to avoid leaks, remove id from PROGRESS.
// maybe save that the task ends in a data base.
return
} else {
println!("Progress {}: {}", id, p);
}
}
thread::sleep(Duration::new(1, 0));
}
}
fn main() {
let w = thread::spawn(|| work(1));
let m = thread::spawn(|| monitor(1));
w.join().unwrap();
m.join().unwrap();
}
You need to register one channel per request thread, because if cloning Receivers were possible the responses might/will end up with the wrong thread if two request are running at the same time.
Instead of having your thread create a channel for answering requests, use a future. A future allows you to have a handle to an object, where the object doesn't exist yet. You can change the input channel to receive a Promise, which you then fulfill, no output channel necessary.

Resources