Scrypto: how to write test passing bucket as a function argument - scrypto

In my blueprint, I have a function for the admin to deposit tokens back into the blueprint token vault.
pub fn deposit(&mut self, amount: Decimal, mut bucket: Bucket) {
assert!(amount <= bucket.amount(), "not enough amount in your bucket");
self.token_vault.put(bucket.take(amount))
}
I know how to generate a new account in my test file, and how to make a method call with badge protected access...
And I have learned from Scrypto-example/nft/magic-card:
https://github.com/radixdlt/scrypto-examples
let (public_key, private_key, account_component) = test_runner.new_allocated_account();
...
let manifest = ManifestBuilder::new(&NetworkDefinition::simulator())
.create_proof_from_account_by_amount(account_component, badge_amount, badge_addr)
.withdraw_from_account_by_amount(account_component, amount, token_addr)
.take_from_worktop(token_addr, |builder, bucket_id| {
builder.call_method(component, func_name, args!(amount, Bucket(bucket_id)))
})
.call_method(
account_component,
"deposit_batch",
args!(Expression::entire_worktop()),
)
.build();
let receipt = test_runner.execute_manifest_ignoring_fee(
manifest,
vec![NonFungibleAddress::from_public_key(&public_key)],
);
println!("{} receipt: {:?}\n", func_name, receipt);
receipt.expect_commit_success();
Then I got this error:
COMMITTED FAILURE: KernelError(InvalidDropNodeVisibility { mode: Application, actor:
Method(Scrypto { package_address: NormalPackage[011784f2e3c4b3dc9d14c850484fc4962f59ea68271e917d2f075c],
blueprint_name: "StableCoin", ident: "deposit" }, ResolvedReceiver { derefed_from:
Some((Global(Component(NormalComponent[02fd2e738e08b33e7d19001684043cd24fe35fda1ddc9429f7051e])), 36)),
receiver: Component([252, 13, 40, 104, 140, 209, 211, 110, 141, 213, 197, 200, 172, 195, 190, 178, 219, 47, 174, 17, 52, 209, 75, 207, 106, 97, 105, 21, 213, 159, 52, 25, 15, 4, 0, 0]) }),
node_id: Bucket(1027) })
But how can I make the bucket variable from my account_component as a function argument?

I solved it... my blueprint function should not include the amount, which has been represented in bucket argument...
pub fn deposit_to_vault(&mut self, bucket: Bucket) {
self.token_vault.put(bucket)
}
then use take_from_worktop_by_amount to get the bucket_id:
.withdraw_from_account_by_amount(user.compo_addr, amount, token_addr)
.take_from_worktop_by_amount(amount, token_addr, |builder, bucket_id| {
builder.call_method(component, func_name, args!(Bucket(bucket_id)))
})
.call_method(
user.compo_addr,
"deposit_batch",
args!(Expression::entire_worktop()),
)
.build();

Related

Kotlin: Applicatives with Extension Functions

From what I understood, Applicatives are classes which implement the method apply, but I've seen a version with functions too. This is what it should look like:
fun <T, R> List<T>.ap(fab: List<(T) -> R>): List<R> = fab.flatMap { f -> this.map(f) }
And, when I am testing it with:
fun main(){
val numbers = listOf(75, 454, 7, 45, 45, 56, 75)
val functions = listOf<(Int) -> Int>({ i -> i * 2 }, { i -> i + 3 })
val result = numbers.ap(functions).joinToString()
println(result)
}
The output is:
150, 908, 14, 90, 90, 112, 150, 78, 457, 10, 48, 48, 59, 78
But the expected output is:
153, 911, 17, 93, 93, 115, 153, 81, 460, 13, 51, 51, 62, 81
Basically, I am applying a list of functions to a normal list, that's what it should do. From what I observed, my applicative did his job only for the first function, but for the other, it didn't... How can I get the expected result, using applicatives? I would like to keep my list of functions the way it is already, or at least to keep it similar at most.

The picture can't display in the google colab

python, pyecharts, google colab
It seems get the picture, but why can's see anything
enter image description here
from pyecharts.globals import CurrentConfig, NotebookType
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
from pyecharts.charts import Bar
from pyecharts import options as opts
# V1 版本开始支持链式调用
bar = (
Bar()
.add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
.add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
.add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
.set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"))
)
bar.render()
# 不习惯链式调用的开发者依旧可以单独调用方法
bar = Bar()
bar.add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
bar.add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
bar.set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"))
# bar.load_javascript()
# bar.render()
bar.render_notebook()

Get content of pouchdb attachment

I saved some vue-files as attachment in my pouchdb. At the start of the application the app should load all vue-files from pouchdb, adding it to router and get render on runtime. My current problem: How can get the content (text) of the vue file, so I can import or parse it at runtime.
import PouchDB from 'pouchdb';
const dbsfc = new PouchDB('db_components');
dbsfc.replicate.from('http://167.86.69.128:5984/single_file_components/', {live: true, retry: true});
dbsfc.getAttachment('login', 'Login.vue', function(err, blob_buffer) {
if (err) {
return console.log(err);
} else {
console.log(blob_buffer);
}
});
What I get in my console:
Uint8Array(6204) [60, 116, 101, 109, 112, 108, 97, 116, 101, 62, 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 119, 114, 97, 112, 112, 101, 114, 32, 102, 97, 100, 101, 73, 110, 68, 111, 119, 110, 34, 62, 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 105, 100, 61, 34, 102, 111, 114, 109, 67, 111, 110, 116, 101, 110, 116, 34, 62, 10, 32, 32, 32, 32, 32, 32, 60, 33, 45, 45, 32, 76, 111, 103, 105, 110, 32, 70, 111, 114, 109, 32, 45, 45, 62, 10, 32, …][0 … 99][100 … 199][200 … 299][300 … 399][400 … 499][500 … 599][600 … 699][700 … 799][800 … 899][900 … 999][1000 … 1099][1100 … 1199][1200 … 1299][1300 … 1399][1400 … 1499][1500 … 1599][1600 … 1699][1700 … 1799][1800 … 1899][1900 … 1999][2000 … 2099][2100 … 2199][2200 … 2299][2300 … 2399][2400 … 2499][2500 … 2599][2600 … 2699][2700 … 2799][2800 … 2899][2900 … 2999][3000 … 3099][3100 … 3199][3200 … 3299][3300 … 3399][3400 … 3499][3500 … 3599][3600 … 3699][3700 … 3799][3800 … 3899][3900 … 3999][4000 … 4099][4100 … 4199][4200 … 4299][4300 … 4399][4400 … 4499][4500 … 4599][4600 … 4699][4700 … 4799][4800 … 4899][4900 … 4999][5000 … 5099][5100 … 5199][5200 … 5299][5300 … 5399][5400 … 5499][5500 … 5599][5600 … 5699][5700 … 5799][5800 … 5899][5900 … 5999][6000 … 6099][6100 … 6199][6200 … 6203]type: "application/octet-stream"__proto__: Uint8Array
My pouchdb doc:
{
"_id": "login",
"_rev": "3-a0a86cc1f4edc56a8bed8982ac00eb8c",
"_attachments": {
"Login.vue": {
"content_type": "application/octet-stream",
"revpos": 2,
"digest": "md5-u0vcUl76jzVfN12h2fAL7g==",
"length": 6204,
"stub": true
}
}
}
What I was expecting:
<template>
<div class="wrapper fadeInDown">
...
</template>
<script>...</script>
<style>
...
</style>
I haven't worked with pouchDB but I suppose you shall change your content type to e.g. "text/plain".
Another option is to convert octet-stream data to text:
let string = new TextDecoder("utf-8").decode(blob_buffer);

Why won't my code store ints into my temps array?

System.out.print("What would you like to decode? ");
String fileName1 = console.next();
System.out.print("Save the results as: ");
resultFileName = console.next();
int token1;
Scanner inFile1 = new Scanner(new
File(fileName1)).useDelimiter("[" + "," + " ]");
List<Integer> temps = new ArrayList<Integer>();
while (inFile1.hasNext()) {
token1 = inFile1.nextInt();
temps.add(token1);
}
for(int i = 0; i <= temps.size() - 1; i++) {
int x = temps.get(i);
System.out.print((char) x);
}
when i run this it says there is a error on "token1 = inFile1.nextInt();"
this is what is in the file: [89, 111, 117, 39, 114, 101, 32, 97, 108, 109, 111, 115, 116, 32, 116, 104, 101, 114, 101, 46, 32, 75, 101, 101, 112, 32, 117, 112, 32, 116, 104, 101, 32, 103, 111, 111, 100, 32, 119, 111, 114, 107, 33]
Use the inFile1.hasNextInt() opposed to the inFile1.hasNext(). This way you can make sure the next value can be interpreted as an int.
I think the inFile1.hasNext() is resolving as true because you still have the character ] left in the file.
The useDelimiter is only used to seperate your ints. So you have to manually parse the [ and ] and call Scanner inFile1 = new Scanner(new
File(fileName1)).useDelimiter(","); for parsing the ints.
Edit: for parsing the '[' for example you can use:
Pattern p = Pattern.compile("[");
scanner.next(p);

Performance decrease with function call

For the following function:
func CycleClock(c *ballclock.Clock) int {
for i := 0; i < fiveMinutesPerDay; i++ {
c.TickFive()
}
return 1 + CalculateBallCycle(append([]int{}, c.BallQueue...))
}
where c.BallQueue is defined as []int and CalculateBallCycle is defined as func CalculateBallCycle(s []int) int. I am having a huge performance decrease between the for loop and the return statement.
I wrote the following benchmarks to test. The first benchmarks the entire function, the second benchmarks the for loop, while the third benchmarks the CalculateBallCycle function:
func BenchmarkCycleClock(b *testing.B) {
for i := ballclock.MinBalls; i <= ballclock.MaxBalls; i++ {
j := i
b.Run("BallCount="+strconv.Itoa(i), func(b *testing.B) {
for n := 0; n < b.N; n++ {
c, _ := ballclock.NewClock(j)
CycleClock(c)
}
})
}
}
func BenchmarkCycle24(b *testing.B) {
for i := ballclock.MinBalls; i <= ballclock.MaxBalls; i++ {
j := i
b.Run("BallCount="+strconv.Itoa(i), func(b *testing.B) {
for n := 0; n < b.N; n++ {
c, _ := ballclock.NewClock(j)
for k := 0; k < fiveMinutesPerDay; k++ {
c.TickFive()
}
}
})
}
}
func BenchmarkCalculateBallCycle123(b *testing.B) {
m := []int{8, 62, 42, 87, 108, 35, 17, 6, 22, 75, 116, 112, 39, 119, 52, 60, 30, 88, 56, 36, 38, 26, 51, 31, 55, 120, 33, 99, 111, 24, 45, 21, 23, 34, 43, 41, 67, 65, 66, 85, 82, 89, 9, 25, 109, 47, 40, 0, 83, 46, 73, 13, 12, 63, 15, 90, 121, 2, 69, 53, 28, 72, 97, 3, 4, 94, 106, 61, 96, 18, 80, 74, 44, 84, 107, 98, 93, 103, 5, 91, 32, 76, 20, 68, 81, 95, 29, 27, 86, 104, 7, 64, 113, 78, 105, 58, 118, 117, 50, 70, 10, 101, 110, 19, 1, 115, 102, 71, 79, 57, 77, 122, 48, 114, 54, 37, 59, 49, 100, 11, 14, 92, 16}
for n := 0; n < b.N; n++ {
CalculateBallCycle(m)
}
}
Using 123 balls, this gives the following result:
BenchmarkCycleClock/BallCount=123-8 200 9254136 ns/op
BenchmarkCycle24/BallCount=123-8 200000 7610 ns/op
BenchmarkCalculateBallCycle123-8 3000000 456 ns/op
Looking at this, there is a huge disparity between benchmarks. I would expect that the first benchmark would take roughly ~8000 ns/op since that would be the sum of the parts.
Here is the github repository.
EDIT:
I discovered that the result from the benchmark and the result from the running program are widely different. I took what #yazgazan found and modified the benchmark function in main.go mimic somewhat the BenchmarkCalculateBallCycle123 from main_test.go:
func Benchmark() {
for i := ballclock.MinBalls; i <= ballclock.MaxBalls; i++ {
if i != 123 {
continue
}
start := time.Now()
t := CalculateBallCycle([]int{8, 62, 42, 87, 108, 35, 17, 6, 22, 75, 116, 112, 39, 119, 52, 60, 30, 88, 56, 36, 38, 26, 51, 31, 55, 120, 33, 99, 111, 24, 45, 21, 23, 34, 43, 41, 67, 65, 66, 85, 82, 89, 9, 25, 109, 47, 40, 0, 83, 46, 73, 13, 12, 63, 15, 90, 121, 2, 69, 53, 28, 72, 97, 3, 4, 94, 106, 61, 96, 18, 80, 74, 44, 84, 107, 98, 93, 103, 5, 91, 32, 76, 20, 68, 81, 95, 29, 27, 86, 104, 7, 64, 113, 78, 105, 58, 118, 117, 50, 70, 10, 101, 110, 19, 1, 115, 102, 71, 79, 57, 77, 122, 48, 114, 54, 37, 59, 49, 100, 11, 14, 92, 16})
duration := time.Since(start)
fmt.Printf("Ballclock with %v balls took %s;\n", i, duration)
}
}
This gave the output of:
Ballclock with 123 balls took 11.86748ms;
As you can see, the total time was 11.86 ms, all of which was spent in the CalculateBallCycle function. What would cause the benchmark to run in 456 ns/op while the running program runs in around 11867480 ms/op?
You wrote that CalcualteBallCycle() modifies the slice by design.
I can't speak to correctness of that approach, but it is why benchmark time of BenchmarkCalculateBallCycle123 is so different.
On first run it does the expected thing but on subsequent runs it does something completely different, because you're passing different data as input.
Benchmark this modified code:
func BenchmarkCalculateBallCycle123v2(b *testing.B) {
m := []int{8, 62, 42, 87, 108, 35, 17, 6, 22, 75, 116, 112, 39, 119, 52, 60, 30, 88, 56, 36, 38, 26, 51, 31, 55, 120, 33, 99, 111, 24, 45, 21, 23, 34, 43, 41, 67, 65, 66, 85, 82, 89, 9, 25, 109, 47, 40, 0, 83, 46, 73, 13, 12, 63, 15, 90, 121, 2, 69, 53, 28, 72, 97, 3, 4, 94, 106, 61, 96, 18, 80, 74, 44, 84, 107, 98, 93, 103, 5, 91, 32, 76, 20, 68, 81, 95, 29, 27, 86, 104, 7, 64, 113, 78, 105, 58, 118, 117, 50, 70, 10, 101, 110, 19, 1, 115, 102, 71, 79, 57, 77, 122, 48, 114, 54, 37, 59, 49, 100, 11, 14, 92, 16}
for n := 0; n < b.N; n++ {
tmp := append([]int{}, m...)
CalculateBallCycle(tmp)
}
}
This works-around this behavior by making a copy of m, so that CalculateBallCycle modifies a local copy.
The running time becomes more like the others:
BenchmarkCalculateBallCycle123-8 3000000 500 ns/op
BenchmarkCalculateBallCycle123v2-8 100 10483347 ns/op
In your CycleClock function, you are copying the c.BallQueue slice. You can improve performance significantly by using CalculateBallCycle(c.BallQueue) instead (assuming CalculateBallCycle doesn't modify the slice)
For example:
func Sum(values []int) int {
sum := 0
for _, v := range values {
sum += v
}
return sum
}
func BenchmarkNoCopy(b *testing.B) {
for n := 0; n < b.N; n++ {
Sum(m)
}
}
func BenchmarkWithCopy(b *testing.B) {
for n := 0; n < b.N; n++ {
Sum(append([]int{}, m...))
}
}
// BenchmarkNoCopy-4 20000000 73.5 ns/op
// BenchmarkWithCopy-4 5000000 306 ns/op
// PASS
There is a subtle bug in your tests.
Both methods BenchmarkCycleClock and BenchmarkCycle24 run the benchmark in a for loop, passing a closure to b.Run. Inside of those closures you initialize the clocks using the loop variable i like this:ballclock.NewClock(i).
The problem is, that all instances of your anonymous function share the same variable. And, by the time the function is run by the test runner, the loop will be finished, and all of the clocks will be initialized using the same value: ballclock.MaxBalls.
You can fix this using a local variable:
for i := ballclock.MinBalls; i <= ballclock.MaxBalls; i++ {
i := i
b.Run("BallCount="+strconv.Itoa(i), func(b *testing.B) {
for n := 0; n < b.N; n++ {
c, _ := ballclock.NewClock(i)
CycleClock(c)
}
})
}
The line i := i stores a copy of the current value of i (different for each instance of your anonymous function).