How to create a child app with parameters in Algorand? - beaker

I want to create a child app as described here, but make it to accept parameters on creation:
from pyteal import *
from beaker import Application, ApplicationStateValue, decorators
class ChildApp(Application):
foo = ApplicationStateValue(
stack_type=TealType.uint64,
)
#decorators.create
def create(self, foo: abi.Uint64):
return Seq(
self.foo.set(foo.get()),
)
class ParentApp(Application):
child: AppPrecompile = AppPrecompile(ChildApp())
#decorators.external
def create_child(self, *, output: abi.Uint64):
return Seq(
InnerTxnBuilder.Execute({
**self.child.get_create_config(),
# ???
}),
output.set(InnerTxn.created_application_id()),
)
The question is – how do I pass those parameters to a child?
From what I see, the only thing that looks suitable, is application_args:
InnerTxnBuilder.Execute({
**self.child.get_create_config(),
TxnField.application_args: [ Itob(42) ],
})
I have to use Itob in this case, because application_args only accepts Bytes values.
This is weird already, but anyway it doesn't work: on attempt to call create_child method I get this:
TransactionPool.Remember: transaction RIOKX6SHD2QC4CW3ZDMVKEWDP7DISFXEGOMQEZOVQQDY6OMMAN6Q:
logic eval error: err opcode executed. Details: pc=60, opcodes===\n' +
'bnz label4\n' +
'err\n' +
'label4:\n'
Which is not helpful at all. I don't understand what am I doing wrong.
So how do I properly pass params to a child app?

Firstly, thank you for trying out Beaker even though it is still in early development! Please don't be afraid to share your feedback on it through it's GitHub repository or Beaker channel on the Algorand Discord server.
From ARC 4 which details the ABI standard:
The method selector must be the first Application call argument (index 0), accessible as txna ApplicationArgs 0 from TEAL (except for bare Application calls, which use zero application call arguments).
Your TxnField.application_args should therefore look something like the following so that your child contract knows which method it should route to upon creation:
TxnField.application_args: [
Bytes(get_method_spec(ChildApp.create).get_selector()),
Itob(Int(42)),
],
Also note that the number 42 must first be wrapped with Int to convert it to a teal type.
You will likely want to pass an argument from the parent to the child on creation. If so, then it'd look more like the following assuming your parent receives an abi.Uint64 argument called my_int_arg:
TxnField.application_args: [
Bytes(get_method_spec(ChildApp.create).get_selector()),
my_int_arg.encode(),
],
You may read more about ARC 4 here.

Related

AnyLogic inject agents from existing population with characteristics

I created a population with objects from a database with individual characteristics.
I am trying that the objects with a specific value are injected into a source for process-modelling.
("ankunftszeit" means "arrival time")
for (mp_lkw l : pop_mp_lkw){
if (l.ankunftszeit == getTime()){
source_mp_lkw.inject(mp_lkw l, 1, false, false);
}
}
But somehow an Error occurs and I cannot find any solution...
It says taht the inject() only accepts integers
The method inject(int) in the type Source<mp_lkw> is not applicable for the arguments (mp_lkw, int, boolean, boolean)
Syntax error on token "l", delete this token
Where is my mistake and how can it be corrected?
Not sure I understand your issue, but if the agents already exist, you shouldn't use a source, instead use an enter block, and then change your code to (even though this code seems like a terrible idea... instead you should use dynamic events but I'm not sure your purpose)
for (mp_lkw l : pop_mp_lkw){
if (l.ankunftszeit == getTime()){
enter.take(l);
}
}

Adding classes to micropython module

In reference to adding module in micropython, I was trying to create a class which has a local method. In the documentation it is given how to add local methods and that the first argument should be of mp_obj_t type which is the data struct itself. However, I was asking how can I pass extra parameters like other methods? I tried using mp_obj_t * args as second argument but STATIC MP_DEFINE_CONST_FUN_OBJ_1 gives error. I tried the same with STATIC MP_DEFINE_CONST_FUN_OBJ_VAR but it does not support passing mp_obt_t as first argument as STATIC MP_DEFINE_CONST_FUN_OBJ_VAR needs an int. I am quite new, so I was asking how to add methods to classes which can accept arguments?
You need MP_DEFINE_CONST_FUN_OBJ_2, since you have 2 arguments.
Something like
STATIC mp_obj_t my_class_func(mp_obj_t self, mp_obj_t arg) {
if (MP_OBJ_IS_SMALL_INT(lhs)) {
const mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(arg);
//...
} else {
//oops, not an int
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(my_class_func_obj, my_class_func);
The best source of samples like this is the source code btw.
To eleaborate on #stijn answer ~ when creating a class, all the MP_DEFINE_CONST_FUN_OBJ_XXXXXX defines work the exact same as they would if you weren't creating a class. The only difference is the first argument of ACTUAL arguments will always refer to self
Here's an example:
mp_obj_t Class_method(mp_uint_t n_args, const mp_obj_t *args) { ... }
That is the standard candidate for:
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Class_method_obj, 1, 3, Class_method);
However, in this case args[0] will be self.
Let's have another example.
mp_obj_t Class_method(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { ... }
That's a prime candidate for this define
MP_DEFINE_CONST_FUN_OBJ_KW(Class_method_obj, 2, Class_method);
The only difference in this case is that the first index of allowed_args needs to automatically be handled as self. Nothing about how you do these things changes, except now the first ACTUAL argument (ie not including n_args or any other "helper" argument) needs to automatically be considered as self. That being said, you will NEVER use MP_DEFINE_CONST_FUN_OBJ_0 with a class method. '_0' means "zero arguments" and a class method will never have zero arguments because it will ALWAYS at least have self. This also means that you have to add one to however many expected arguments you have on the python end. If your python version accepts 3 arguments ~
(red, green, blue)
then your C_MODULE define has to start at 4 because it's going to get
(self, red, green, blue)

MockModule's mock not being called?

I have a module that uses random numbers in it. For testing purposes, I want to set the random number generator to provide a given number before it's called. My code under test includes the dependency like so:
use Math::Random::MT qw(rand);
And uses it like so:
my $currdice = int(rand($right) + 1);
And my mocking is done like so:
my $mockRand;
BEGIN {
$mockRand = Test::MockModule->new('Math::Random::MT');
use_ok(LogiDice);
}
$mockRand->mock('rand' => sub {return 1});
($successes, $output) = LogiDice::roll("3d10","ww");
ok($successes == 0, "WhiteWolf mode can return 0 successes") or diag ("Reported " . $successes . " successes instead.");
I'm getting random numbers of successes instead of always getting 0 (since the random number should always be 1, which should always be a failure). Is this something to do with how I did qw(rand)? Am I using MockModule incorrectly? Should I be using MockModule at all? I tried MockObject before I found MockModule but that wasn't working either.
So, what I think happens is...
You make your mock wrapper
Then you call "use_ok(LogiDice)", which triggers "Math::Random::MT qw(rand);" and immediately pulls a copy of "rand" into it's own namespace
Your mock call replaces MT::rand (but not affecting which already has a direct reference to the old "rand")
It would probably work if you move "use_ok" after your call to mock "rand". Alternatively, one could make LogiDice not import "rand" into it's own namespace, and always refer to MT::rand.

Can data be saved between calls to the openCPU server?

I understand that the interface to OpenCPU is RESTful. Nevertheless, I would like to save data between function calls, if possible.
I naively created the following package:
vals <- c()
fnInit <- function() {
vals <<- c('a','b','c')
}
but I got the error: cannot change value of locked binding for 'vals' when I called the fnInit function. I understand why this is happening.
I then tried:
fnBoth <- local({
vals <- c('a','b','c')
function(which) {
if (which == 0) {
vals
} else if (which == 1) {
vals <<- c(vals,'d')
vals
}
}
})
but every time I POST to the fnBoth function with which = 1, I get the same response:
[1] "a" "b" "c" "d"
If I call the function again, I get the same answer. So, it would seem that the value vals is being reset each time.
My question is: Can data be saved between function calls? The above attempts are not meant to be exhaustive - maybe there's another technique? Or, should I simply save the value to disk?
Thanks
It is not completely clear to me what you are trying to accomplish, perhaps you can elaborate a bit on the type of application you wish to build.
OpenCPU supports chaining of function calls to calculate e.g. f(g(x), h(y)). This is done by passing the session ID of a completed call as an argument to a subsequent one. Have a look at the docs about argument formats: https://public.opencpu.org/api.html#api-arguments. It includes an example that illustrates this by calculating summary(read.csv("mydata.csv")):
#upload local file mydata.csv
curl https://public.opencpu.org/ocpu/library/utils/R/read.csv -F "file=#mydata.csv"
#replace session id with returned one above
curl https://public.opencpu.org/ocpu/tmp/x067b4172/R/.val/print
curl https://public.opencpu.org/ocpu/library/base/R/summary -d 'object=x067b4172'
The first request calls the read.csv function which returns a dataframe. In the last line, we call the summary function where we set the object argument equal to the output of the previous call (i.e. the data frame) by passing the session ID.

Cannot access the parameter of a Menu.param from a Lift Snippet

I'm trying to extract the parameter from a Lift Menu.param within a snippet so that I can use it to create a named Comet. However, I get a NullPointerException when I try to pass the parameter to the snippet using SnippetDisptach in my Boot.scala, as suggested here:
http://comments.gmane.org/gmane.comp.web.lift/44299
I've created the Menu item as follows:
object AnItemPage {
// create a parameterized page
def menu = Menu.param[Item]("Item", "Item",
s => fetchItem(s), item => item._id.toString) / "item"
private def fetchItem(s:String) : Box[Item] = synchronized {
ItemDAO.findById(ObjectId.massageToObjectId(s))
}
}
I've added the menu to SiteMap. I've also created a Snippet which I would like to pick up the Item parameter. (I'm using fmpwizard's InsertNamedComet library here):
class AddCometItemPage(boxedItem: Box[Item]) extends InsertNamedComet with DispatchSnippet{
val item : Item = boxedItem.openOr(null)
override lazy val name= "comet_item_" + item._id.toString
override lazy val cometClass= "UserItemCometActor"
def dispatch = null
}
My next step is to crate an instance of this class as demonstrated by David Pollak here:
http://comments.gmane.org/gmane.comp.web.lift/44299
This is what I have added to my Boot.scala:
LiftRules.snippetDispatch.append {
case "item_page" => new AddCometItemPage(AnItemPage.menu.currentValue)
}
My item.html references this snippet:
<div class="lift:item_page">
I get the following null pointer exception when I compile and run this:
Exception occurred while processing /item/5114eb4044ae953cf863b786
Message: java.lang.NullPointerException
net.liftweb.sitemap.Loc$class.siteMap(Loc.scala:147)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.siteMap(Menu.scala:170)
net.liftweb.sitemap.Loc$class.allParams(Loc.scala:123)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.allParams(Menu.scala:170)
net.liftweb.sitemap.Loc$class.net$liftweb$sitemap$Loc$$staticValue(Loc.scala:87)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.net$liftweb$sitemap$Loc$$staticValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.paramValue(Loc.scala:85)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.paramValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.currentValue(Loc.scala:114)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.currentValue(Menu.scala:170)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:107)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:106)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.common.Full.map(Box.scala:553)
net.liftweb.util.NamedPF$.applyBox(NamedPartialFunction.scala:97)
net.liftweb.http.LiftRules.snippet(LiftRules.scala:711)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.http.LiftSession.net$liftweb$http$LiftSession$$findSnippetInstance(LiftSession.scala:1505)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1670)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1669)
Has anybody any idea where I'm going wrong? I've not been able to find a lot of information on Menu.param.
Thank you very much for your help.
f
I have never tried what you are doing, so I am not sure the best way to accomplish it. The way you are using the Loc Param, you are extracting a variable from a URL pattern. In your case, http://server/item/ITEMID where ITEMID is the string representation of an Item, and which is the value that gets passed to the fetchItem function. The function call will not have a value if you just arbitrarily call it, and from what I can see you are requesting a value that is not initialized.
I would think there are two possible solutions. The first would be to use S.location instead of AnItemPage.menu.currentValue. It will return a Box[Loc[Any]] representing the Loc that is currently being accessed (with the parameters set). You can use that Loc to retrive currentValue and set your parameter.
The other option would be to instantiate the actor in your snippet. Something like this:
item.html
<div data-lift="AnItemPage">
<div id="mycomet"></div>
</div>
And then in your AnItemPage snippet, something like this:
class AnItemPage(item: Item) {
def render = "#mycomet" #> new AddCometItemPage(item).render
}
I haven't tested either of those, so they'll probably need some tweaking. Hopefully it will give you a general idea.