HI
Rholang
为你打开Rholang世界的大门
V1.0
中文版
Copyleft © https://rholang-china.org
Rholang 简介
Rholang是一门基于Rho calculus (Rho 演算) 的并发语言,专为分布式系统设计。
Rholang程序是完全异步的,由消息传输机制驱动执行。
Rholang不只是一门智能合约语言,可用于其它计算环境中。
Copyleft © https://rholang-china.org
Rholang 源于 Rho Calculus
传统的计算机语言基于图灵机和自动机的概念,适于描述单个自动机的行为。
而Pi Calculus(Pi演算)则为开放而自由的网络而生,描述分布式的网络环境。
Rho calculus是在Pi Calculus的基础上,增加了Name(名字)和Process(过程)的转换方法,称之为Reflection(反射性)。
Copyleft © https://rholang-china.org
Rho calculus
P,Q,R ::=0 //nil or stopped process
| for ( ptrn1 <- x1; ... ; ptrnN <- xN ).P //input guards
| x!( Q ) //output
| \*x\ //dereferenced or unquoted name
| P|Q //parallel composition
x,ptrn ::= @P //name or quoted process
Copyleft © https://rholang-china.org
目录
Copyleft © https://rholang-china.org
Rholang环境准备
Copyleft © https://rholang-china.org
方法1:在本地运行Rnode节点 (推荐)
1.本地运行Rnode节点(以Mac为例),下载最新版的Rnode客户端,下载地址:https://developer.rchain.coop/。(注意请下载文件名为 .TGZ的客户端,本教程中使用的均为该客户端)
2.打开“终端”,通过命令进入解压缩后的文件夹,找到bin文件夹并进入。
3.在bin文件夹下通过命令:./rnode run -s -n 来运行一个单独的本地节点(Stand Alone)。
4.将写好的智能合约存入文件夹,通过命令:./rnode eval /路径/xxx.rho运行智能合约。
Copyleft© https://rholang-china.org
Cryptofex可以在Windows、Mac和Linux上本地运行,下载地址:https://cryptofex.io/
方法2:Cryptofex IDE
Copyleft © https://rholang-china.org
方法3:使用Rholang在线Interpreter
在线Interpreter不需要配置任何环境就可以直接在网页端写出智能合约并运行,网页链接:https://rchain.cloud
Send & Receive
01
Copyleft © https://rholang-china.org
Send
1. a!(P)指Send一次,a!!(P) 指持续Send
2. Send 可以理解为:一个Process被发送/持续发送到目标Name中,换个说法是:目标Name被放入/持续放入了一个Process
3. 一个最常见的Send:stdout!(P),作用是:打印到屏幕
4. stdout(`rho:io:stdout`)是Rholang的Power Box,相当于标准库
Copyleft © https://rholang-china.org
new HelloWorld, stdout(`rho:io:stdout`) in {
HelloWorld!("Hello, world!")|
for (@text <- HelloWorld) {
stdout!(text)
}
}
//运行结果:屏幕上出现“Hello,world!”
Copyleft © https://rholang-china.org
Send
Receive
1. for (a <- b) {Q} 指Receive一次,即:目标Name里的Process被取走后,触发process Q
2. for (a <= b) {Q} 指持续Receive,即:只要目标Name里有Process,就被取走,取走后触发Process Q
3. contract b(a) = {P}是for (a <= b) {P}的语法糖
Copyleft © https://rholang-china.org
//用for接收消息
new pizzaShop, stdout(`rho:io:stdout`) in {
pizzaShop!("2 medium pies")|
pizzaShop!("5 medium pies")|
for (order <- pizzaShop) {
stdout!("Order Received.")
}
}
//用for持续接收消息
new pizzaShop, stdout(`rho:io:stdout`) in {
for (order <= pizzaShop) {
stdout!("Pizza Order Received")
}|
pizzaShop!("one hot chocolate")|
pizzaShop!("two large latte's please")
}
//用contract持续接收消息
new coffeeShop, stdout(`rho:io:stdout`) in {
contract coffeeShop(order) = {
stdout!("Coffee Order Received")
}|
coffeeShop!("one hot chocolate")|
coffeeShop!("two large cappuccinos please")
}
#5:即使pizzaShop被放入了两个Process,for也只能取走一个
#12:只要 pizzaShop被放入了Process,就会被取走
#21:只要coffeeShop 被放入了Process,contract coffeeShop就被触发,Process就会被取走
Copyleft © https://rholang-china.org
Receive
如何更深入地理解Send 和 Receive?(难点)
1. a!(Q)
Process Q 向 Name a的传递
2. for (@c <- a ) {P}
a里面的Process被传递到了@c这个Name里 ✗
a里的Process被消耗,同时c被赋值(bind)为a里的Process,可以直接使用,@c 成为一个有作用域的Name ✓
new a, stdout(`rho:io:stdout`) in {
a!(1)|
for (@b <- a) {
for (@c <- @b) {
stdout!([c, "index1"])
}|
stdout!([b,"index2"])
}
}
3. a!(Q)|for (@c < -a) {P}
包含同一个Name的一次Send 和 一次Receive 组成了一个Comm Event
//运行结果是:[1, "index2"]
//@b里没有Process,所以@c取不到值
Copyleft © https://rholang-china.org
for (p1Pushups <- player1; p2Pushups <- player2) {
stdout!("The winner is...")
}
很多时候,要得到两个或更多数据源的数据才能够执行一个计算。比如,两个运动员赛跑,要得到他们两个的成绩之后,才能判断输赢。
在Rholang里,这种情况要使用join运算符,也就是#1中两个receive中间的 ;
Join Operator
Copyleft © https://rholang-china.org
new aliceLaunch, bobLaunch, stdout(`rho:io:stdout`) in {
for (x <- aliceLaunch) {
for (y <- bobLaunch) {
stdout!("Launching the rocket")
}
}|
aliceLaunch!("launch")|
bobLaunch!("launch")
}
错误实现 ✗
一旦Alice发现问题,想要取消发送指令,她无法做到终止发射。
例子1: Rocket Launch
一架火箭准备被发射,程序设定,只有它在收到Alice 和 Bob 两个飞行员发出的发射指令后,才能被触发发射
Copyleft © https://rholang-china.org
Join Operator
new aliceLaunch, bobLaunch, stdout(`rho:io:stdout`) in {
for (x <- aliceLaunch; y <- bobLaunch) {
stdout!("Launching the rocket")
}|
aliceLaunch!("launch")|
bobLaunch!("launch")
}
正确实现 ✓
#2中,x、y都Receive到指令后才能触发#3,在那之前,aliceLaunch 和 bobLaunch里的消息均不会被取走。
例子1: Rocket Launch
Copyleft © https://rholang-china.org
Join Operator
两名玩家独立发送消息,谁的消息先被收到,谁就输了
例子2:Patience Game
错误实现 ✗
new p1, p2, stdout(`rho:io:stdout`) in {
p1!("Send any message")|
p2!("Hope I win")|
for (m2 <- p2) {
for (m1 <- p1) {
stdout!("Player one wins!")
}
}|
for (m1 <- p1) {
for (m2 <- p2) {
stdout!("Player two wins!")
}
}
}
#4和#9并行,此时,p1、p2里的消息都已经被取走,#5和#10没有一个能被触发。
Copyleft © https://rholang-china.org
Join Operator
例子2:Patience Game
正确实现 ✓
new p1, p2, a, stdout(`rho:io:stdout`) in {
p1!("Send any message")|
p2!("Hope I win")|
a!(1)|
for (m2 <- p2; _ <-a) {
for (m1 <- p1) {
stdout!("Player one wins!")
}
}|
for (m1 <- p1; _ <-a) {
for (m2 <- p2) {
stdout!("Player two wins!")
}
}
}
a的引入起到了“开关”的作用,配合Join运算符的使用,实现程序目的
Copyleft © https://rholang-china.org
Join Operator
例子3: Dining Philosophers and Deadlock
什么是Deadlock?
多个进程或线程相互等待对方的资源,在等到对方资源之前,也不会释放自己的资源,这样造成循环等待的现象,若无外力作用,他们都无法推进下去,这样就产生了deadlock。
Dining Philosophers 就是非常经典的Deadlock问题。
在下面的案例中,把Dining Philosophers简单化:两名哲学家,分别坐在桌子的东边和西边,共享一副刀叉,而同时拥有刀叉的一方方能就餐。
Copyleft © https://rholang-china.org
Join Operator
new philosopher1, philosopher2, north, south, knife, spoon in {
north!(*knife)|
south!(*spoon)|
for (@knf <- north) {
for (@spn <- south) {
philosopher1!("Complete!")|
north!(knf)|
south!(spn)
}
}|
for (@spn <- south) {
for (@knf <- north) {
philosopher2!("Complete!")|
north!(knf)|
south!(spn)
}
}
}
错误实现 ✗
例子3: Dining Philosophers and Deadlock
Copyleft © https://rholang-china.org
Join Operator
new philosopher1, philosopher2, north, south, knife, spoon in {
north!(*knife)|
south!(*spoon)|
for (@knf <- north; @spn <- south) {
philosopher1!("Complete!")|
north!(knf)|
south!(spn)
}|
for (@spn <- south; @knf <- north) {
philosopher2!("Complete!")|
north!(knf)|
south!(spn)
}
}
正确实现 ✓
例子3: Dining Philosophers and Deadlock
Copyleft © https://rholang-china.org
Join Operator
并行 和 串行
02
Copyleft © https://rholang-china.org
什么是并行
在Rholang中,所有的Process都是并行的,Process之间用|来连接。
new a in {
a!(1)|
a!(2)|
for(@x<-a){Nil}|
if(P){Q}
else{R}|
contract a(b)={P}
}
Copyleft © https://rholang-china.org
并行的特点
new a, stdout (`rho:io:stdout`) in{
a!(1)|
a!(2)|
a!(3)|
a!(4)|
a!(5)|
for(@x<=a){
stdout!(x)
}
}
并行有两个特点:
1.所有Process都会执行。
2.并行执行没有先后顺序,是随机的。
#2 #3 #4 #5 #6 #7是并行的,所以输出顺序是随机的。
例子1: 随机输出
Copyleft © https://rholang-china.org
new a,b,stdout (`rho:io:stdout`) in{
a!(1)|
for(@x<-a){
b!(x+1)|
stdout!(x)
}|
for(@y<-b){
stdout!(y)
}
}
Rholang中如何做到顺序执行
通过参数的传递来做到顺序执行。
例子2: 顺序输出
- a里有Process, #3 才会执行
- b里有Process, #6才会执行。
Copyleft © https://rholang-china.org
Process & Name
03
Copyleft © https://rholang-china.org
Process和Name
Process是一段Rholang代码,比如实现某种功能的完整代码,或是一段很短的代码片段。
举几个例子:
- Send:stdout!(" Sup Rholang? ")
- 最小的Process,表示什么都不做:Nil
- 接到消息后什么都不做:for(msg <- phone){ Nil }
- Ground Terms:“Hello World”、“Hi, Rholang”、1、 ......
All computation done by processes communicating over names
所以在Rholang中除了Process就是Name,且两者可以相互转换。
Copyleft © https://rholang-china.org
Name are quoted processes,Name又被称为Channel,用来传输和存储Process。
在Rholang中,有两种形式的name:
一种是使用new和for语法定义的Name,如
- new a in { for ( b <- a) { Nil } } 中的a和b都是新定义的Name。
另一种是被引用的Process,用@标记,如
- 引用了Ground Term的name:@“Hello World”
- 最小的name:@Nil
- 引用了具体的process的name:@P、@{a! (P)}、@{for (b <- a) {P}}
Process和Name
Copyleft © https://rholang-china.org
new alice, bob, stdout(`rho:io:stdout`) in {
alice!("How to program: Change stuff and see what happens.")|
for (message <- alice) {
bob!(*message)
}|
for (message <- bob) {
stdout!(*message)
}
}
例子1:Telephone Game
Alice向Bob传递消息,Bob收到后将它打印出来。
alice、bob、message是Name;
“How to program: Change...... ”、*message以及整段代码是Process。
Process和Name
In rholang we send processes and receive names.
在 a! ( P ) 中,a是Name,P是Process;
在for(b <- a) { P }中,a和b是Name,P是Process。
例子中,哪些Name,哪些是Process?
Copyleft © https://rholang-china.org
用@符号来标记Process,就转换成了Name,如@P ;
用*符号标记来Name,就转换成了Process,如*x ;
Process通过Name传递。
Process与Name的转换
Copyleft © https://rholang-china.org
Process与Name的转换
process | name |
---|---|
Nil | @Nil |
*importantData | importantData |
"BobsPhone" | ackChannel |
*@"BobsPhone" | @*ackChannel |
Copyleft © https://rholang-china.org
new a, b, stdout(`rho:io:stdout`) in {
a!(*b)|
b!(1)|
for (@c <- a) {
stdout!(c)
}
}
//结果: Unforgeable(0x0ef84f0816679bafc4365da3e28d2ea9f674823f0dc7709dd3c74d2b8ac0a038)
a,b是name,c是process
#2 当使用Send语句时,b需要转化为process,被*标记
*b并不是对应b中存放的process,而是将b由name转换成process
#4 在for语法中,箭头左侧是name,c用@标记
Process与Name的转换
Copyleft © https://rholang-china.org
for (@n <- m) {stdout!(n)}
Process与Name的转换
通常,在for语句中,出现在箭头左侧的Name,如果更多的以Process的形式被传递和存储,则使用被引用的Process,如左侧例子中的@n。
同样的,在contract语句中,括号里面的Name,如果更多的以Process的形式被传递和存储,则使用被引用的Process,如右侧例子中的@a。
但当Name用来作为确认程序执行结束或返回结果用时(如ack、return),不需要进行Process与Name的转换,如右侧例子中的ack。
contract example(@a, ack) = {
stdout!(a)|
ack!(Nil)
}
Copyleft © https://rholang-china.org
new get, initial, stdout(`rho:io:stdout`) in {
initial!(0)|
contract get(@"new", @arg, ack) = {
for (@old <- initial) {
initial!(arg)|
ack!(old)
}
}|
new ack in {
get!("new", 1, *ack) |
for (_ <- ack) {
stdout!("The process had finished.")
}
}
}
注意程序中get、initial、“new”、@arg、 ack、 @old的用法
Process与Name的转换
Copyleft © https://rholang-china.org
如果Process是等价的,那被引用后形成的Name就是等价的
1. @{P|Q}、@{Q|P}、@{P|Q|Nil}等价
|是并行,没有先后顺序,所以P|Q、Q|P、P|Q|Nil 是等价的Process
2.@{ for (x <- chan) {P} } 与 @{ for (z <- chan) {P} } 等价
x、z是for 语句中的Bind Variable,所以for (x <- chan) {P}、for (z <- chan) {P}是等价的Process
Name等价
Copyleft © https://rholang-china.org
3. @{8+2} 与 @{5+5}等价
Name等价
new stdout(`rho:io:stdout`) in {
for (a <- @{8+2}) {
stdout!(*a)
}|
@{5+5}!("Hello")
}
Evaluating:
new x0 in {
@{(5 + 5)}!("Hello") |
for( @{x1} <- @{(8 + 2)} ) {
x0!(x1)
}
}
"Hello"
在名字被使用之前,先进行运算,运算结果(也是Process)等价,则被引用的形成的Name等价。运算包括:
算术运算:+, -, *, /
关系运算:>, >=, <, <=, ==, !=
逻辑运算符:and, or, not
匹配运算符:P match Q
Copyleft © https://rholang-china.org
Name 的类型
04
Copyleft © https://rholang-china.org
new pizzaShop, stdout(`rho:io:stdout`) in {
contract pizzaShop(order) = {
stdout!("Order Received.")
}
}|
pizzaShop!("Extra bacon please")|
pizzaShop!("Hawaiian Pizza to go")
#1 pizzaShop只在new后面的{...}内起作用,在外部无法对pizzaShop进行操作
约束变量:指在某Process中定义,只在该Process之内起作用的Name。
约束变量和自由变量
Bind Variable & Free Variable
new a {P}
for(a<-b){P}
contract b(a)={P}
对于P来说,a均为约束变量,只在P内起作用
错误实现
✗
#6 #7 pizzaShop在这里未被定义,会报错
提交订单
Copyleft © https://rholang-china.org
new pizzaShop, stdout(`rho:io:stdout`) in {
contract pizzaShop(order) = {
stdout!("Order Received.")
}|
pizzaShop!("Extra bacon please")|
pizzaShop!("Hawaiian Pizza to go")
}
// 运行结果
// "Order Received."
// "Order Received."
正确实现
✓
提交订单
Copyleft © https://rholang-china.org
约束变量和自由变量
Bind Variable & Free Variable
自由变量:指在某Process之外被定义,那么对该Process而言,这个Name是自由变量。
new b in {Q|for (a <- b) {P}}
new b in {Q|contract b(a) = {P}}
对于P来说,b均为自由变量。
在包含P的更大作用域内被定义,不仅在过程P内起作用,在Q内也起作用。
Copyleft © https://rholang-china.org
约束变量和自由变量
Bind Variable & Free Variable
所有Name在被定义时,被约束在其后的整个Process,但对于其内部的Process是自由变量
new a,stdout(`rho:io:stdout`) in {
a!(Nil)|
a!(Nil)|
for (x <- a) {P}|
contract a(y) = {Q}
}
a对于整个Process而言是约束变量,对于P、Q而言是自由变量
Copyleft © https://rholang-china.org
约束变量和自由变量
Bind Variable & Free Variable
for (x <- y){Nil}
约束
自由
都不是
for (y <- x){Nil}
约束
自由
都不是
new x in { x!(true) }
约束
自由
都不是
contract x(y) = { Nil }
约束
自由
都不是
contract y(x) = { Nil }
约束
自由
都不是
在以下Process中,x是什么变量
✓
✓
✓
✓
✓
Copyleft © https://rholang-china.org
约束变量和自由变量
Bind Variable & Free Variable
-
Unforgeable Name 是Object Capability Security Model (OCAP) 里的一个核心概念
-
出于安全的考虑,在一个Process内部定义的Name不应该被外部访问到,除非有意通过消息机制传递出去。
Copyleft © https://rholang-china.org
Unforgeable Name
Unforgeable Name的定义
用new定义的Name是Unforgeable Name,由一串独一无二的字符表示。可以理解为身份证系统中,同名的人身份ID互不相同。
new a,stdout(`rho:io:stdout`) in{
stdout!(*a)|
new a in{
stdout!(*a)
}
}|
new a,stdout(`rho:io:stdout`) in{
stdout!(*a)
}
// 运行结果
// Unforgeable(0x729d3a68aaf4b4b4985b168f95626d2842cc4e3a972e265bc2538fbf1c83db58)
// Unforgeable(0x46404982fa2da2ba74ac7b6816eca1af46a8ab5880bfdf73cacf4f794262a775)
// Unforgeable(0x5ab9526e8bcc709e85e914ba96ad09a7e90e92258b9ca087f4ca754eb0341df4)
注:每次运行,Unforgeable Name都不一样
Unforgeable Name
用new定义的Name
Copyleft © https://rholang-china.org
用for和contract定义的Name,不是Unforgeable Name,可以理解为昵称或代号。
new a,stdout(`rho:io:stdout`) in{
stdout!(*a)|
a!(100)|
for(x<-a){
stdout!(*x)
}
}
// 运行结果
// Unforgeable(0x6f2df38e2d7fa3cc4f7f40cbede8834a069ac6d52a4b8f9825fd5ed5fa043ce6)
// 100
Unforgeable Name
用for和contract定义的Name
for 定义的Name
Copyleft © https://rholang-china.org
Unforgeable Name
Unforgeable Name 的传递
- Name可以反射为Process (a是Name,那么*a是Process)
- 通过Unforgeable Name 的传递,可以实现Process的传递。传递Unforgeable Name就相当于把该Name相关的Process都共享给了另一个Name。
new a, b in {
b!(*a)|
for (x <- b) {
x!(P)
}|
for (y <- a) {Q}
}
new a in {
a!(P)|
for (x <- a) {Q}
}
=
#3 先被触发,x被赋值为a的Unforgeable Name
#4 *x与*a等价,因此{x!(P)}与{a!(P)}等价,从而#6 被触发
Copyleft © https://rholang-china.org
new alice, bob, stdout(`rho:io:stdout`) in {
alice!(*bob)|
bob!("Bob,You are the best. From Charlie")|
stdout!(["un1 ", *bob])|
for (bobCh <- alice) {
for (@letter <- bobCh){
stdout!(letter)
}|
stdout!(["un2",*bobCh])
}
}
- alice, bob, bobCh, @letter中哪些Name有Unforgeable Name?
- 以上两个智能合约输出结果一样吗?
Unforgeable Name
Unforgeable Name 的传递
new alice, bob, stdout(`rho:io:stdout`) in {
alice!(*bob)|
stdout!(["un1",*bob])|
for (@letter <- bob){
stdout!(letter)
}|
for (bobCh <- alice) {
bobCh!("Bob,You are the best. From Charlie")|
stdout!(["un2",*bobCh])
}
}
Charlie给Bob写了一封信,Alice帮Bob读信
Charlie写了一封信,Alice帮他寄给Bob
#2 Bob的Unforgeable Name发送给了Alice,从而Alice可以对Bob读和写
Copyleft © https://rholang-china.org
- 每一个智能合约部署到区块链后,对所有人都是可见的。从区块链上读到的合约内容中,用new定义的Name以一串字符(Unforgeable Name)表示。
- Unforgeable Name的生成不可预测,互不相同。
- It is impossible to guess the name of a process, and thereby interact with that process. 链上智能合约中包含很多可见的Unforgeable Name,仅通过Unforgeable Name不可调用和触发该Name。(必须通过该Unforgeable Name在区块链上的Uri才能调用和触发它,每一个Unforgeable Name 的Uri在区块链上不可查,也不可预测。详见智能合约与区块链的交互。)
Unforgeable Name
Unforgeable Name在区块链上的应用
Copyleft © https://rholang-china.org
new oldHen, round, counter, stdout(`rho:io:stdout`) in {
contract oldHen ( ack ) = {
round!(1)|
for (@round_ <= round) {
counter!(1)|
if (round_ < 4) {
for (@counter_ <= counter){
if(counter_ < 4 ){
counter!( counter_ + 1 )|
stdout!(["counter",counter_ ])
}
else {
round!( round_ + 1)|
stdout!(["round", round_ ])
}
}
}
}
}|
oldHen!(1)
}
计数器
每轮都是一个从1到3的计数器,一共3轮
错误实现
✗
More Cases
#4 "<="相当于有多个Process (#4-#18,称为P1)在等待round里的值。
#7 "<="相当于有多个Process (#7-#16,称为P2)在等待counter里的值。
一旦某P1被触发,counter就被放入1。由于counter的作用域是所有P2,因此其他P1里的P2就有可能被触发,从而counter的结果变成乱序的死循环。
Copyleft © https://rholang-china.org
……
P1
……
P2
P2
P2
P1
……
P2
P2
P2
P1
……
P2
P2
P2
counter!(1)
counter!(1)
counter!(1)
More Cases
计数器
每轮都是一个从1到3的计数器,一共3轮
错误实现示意图
Copyleft © https://rholang-china.org
可能触发任意等待中的P2
new oldHen, round, stdout(`rho:io:stdout`) in {
contract oldHen ( ack ) = {
round!(1)|
for (@round_ <= round) {
if (round_ < 4) {
new counter in{
counter!(1)|
for (@counter_ <= counter){
if(counter_ < 4 ){
counter!( counter_ + 1 )|
stdout!(["counter",counter_])
}
else {
round!( round_ + 1)|
stdout!(["round", round_])
}
}
}
}
}
}|
oldHen!(1)
}
每一个P1(#4 -20)里定义的counter都不同,作用域为该P1里的Q(#6-18)。
每一个P1里有多个P2(#8-17)在等待counter里的值。
一个P1里的counter只能触发该P1里的P2,不能触发其他P1里的P2
计数器
每轮都是一个从1到3的计数器,一共3轮
正确实现
✓
More Cases
Copyleft © https://rholang-china.org
计数器
每轮都是一个从1到3的计数器,一共3轮
More Cases
……
P1
P1
P1
……
P2
P2
P2
counter1!(1)
……
P2
P2
P2
counter2!(1)
……
P2
P2
P2
counter3!(1)
Q
Q
Q
正确实现示意图
Copyleft © https://rholang-china.org
✗
在这个例子中,因为"<="的特殊性,由变量类型导致的错误非常隐蔽,这就提醒我们在定义name时应该注意其作用范围。
这个计数器有没有更好的实现方法?
More Cases
用 Join Opertator的方法
计数器
每轮都是一个从1到3的计数器,一共3轮
Copyleft © https://rholang-china.org
Contract Factory
05
Copyleft © https://rholang-china.org
关于Contract Factory
1. Contract Factory是一组定义好的合约
2. 在面向对象编程的语言里,经常使用封装(数据+方法)的技术,来模拟现实世界的业务逻辑,
在Rholang里,此项功能是用Contract Factory来实现的
3. 通常,Contract Factory有两种写法,示例如下:
// Separation of Powers
// line4、line5被触发时,method1 与 method2 会被分别传入unforgeable name
contract factory(method1, method2) = {
contract method1(ack) = { ... }
|
contract method2(ack) = { ... }
}
// Control Panel
// 只有factory拥有unforgeable name
contract factory(cPanel) = {
contract @[cPanel, "method1"](ack) = { ... }
|
contract @[cPanel, "method2"](ack) = { ... }
}
Copyleft © https://rholang-china.org
例子1:计数器
从0开始、可被重置的计数器
new currentCount, increase, reset, stdout(`rho:io:stdout`) in {
currentCount!(0)|
contract increase(ack) = {
for (old <- currentCount) {
currentCount!(*old + 1)|
ack!(*old)
}
}|
contract reset(ack) = {
for (old <- currentCount) {
currentCount!(0)|
ack!(*old)
}
}|
new ack in {
increase!(*ack)|
for (_ <- ack) {
increase!(*ack)|
for (_ <- ack) {
increase!(*ack)|
for (_ <- ack) {
increase!(*ack)|
for (_ <- ack; count <- currentCount) {
stdout!(*count)
}
}
}
}
}
}
#3:设置初始值
#5-10:触发后,计数器+1
#12-17:触发后,计数器重置
#19-26:对合约的调用
用简单的Contract方法实现
关于Contract Factory
Copyleft © https://rholang-china.org
new counterFactory, stdout(`rho:io:stdout`) in {
contract counterFactory(increase, reset) = {
new currentCount in {
currentCount!(0)|
contract increase(ack) = {
for (old <- currentCount) {
currentCount!(*old + 1)|
ack!(*old)|
stdout!(*old)
}
}|
contract reset(ack) = {
for(old <- currentCount){
currentCount!(0)|
ack!(*old)
}
}
}
}|
new ack, AliceIncrease, AliceReset in {
counterFactory!(*AliceIncrease,*AliceReset)|
AliceIncrease!(*ack)|
// AliceIncrease!(*ack)|
// AliceIncrease!(*ack)|
AliceIncrease!(*ack)
}|
new ack, BobIncrease, BobReset in {
counterFactory!(*BobIncrease,*BobReset)|
BobIncrease!(*ack)|
// BobIncrease!(*ack)|
// BobIncrease!(*ack)|
BobIncrease!(*ack)
}
}
#3:counterfactory包含的两个功能:增加、重置
#7-13:触发后,计数器+1
#15-22:触发后,计数器重置
#25-27:Alice对counterfactory的调用,必须调用过#3后,才能调用#7/#15
#32-38:Bob对counterfactory的调用,必须调用过#3后,才能调用#7/#15
用Contract Factory的方法实现
例子1:计数器
关于Contract Factory
Copyleft © https://rholang-china.org
两种实现方法有什么区别?
通过使用Contract Factory,把计数器增加和重置的功能定义好、封装,不同的合约调用者(Alice与Bob)可以各自独立地调用任意功能。
例子1:计数器
Copyleft © https://rholang-china.org
关于Contract Factory
传入通道和传出通道
传入通道和传出通道的本质其实是通过Unforgeable Name的传递来完成对相应合约的触发。
“
”
Copyleft © https://rholang-china.org
new factory in {
contract factory(method1, method2) = {
contract method1(ack) = {
Nil
}|
contract method2(ack) = {
Nil
}
}|
new a, b in {
factory!(*a, *b)|
a!(1)|
b!("Hello")
}
}
传入通道中Unforgeable Name的传递
#3:method1和method2被bound在contract factory里面,没有Unforgeable Name
#12/13:method1被赋值为a的Unforgeable Name,method2被赋值为b的Unforgeable Name
#14/15:把某个Process发送给a,就相当于把
它发送给method1,于是contract method1 被触发,contact method2的触发同理。
Copyleft © https://rholang-china.org
传入通道和传出通道
new factory in {
contract factory(x, y) = {
new method1, method2 in {
x!(*method1)|
y!(*method2)|
contract method1(ack) = {
Nil
}|
contract method2(ack) = {
Nil
}
}
}|
new a, b in {
factory!(*a, *b)|
for (ack1 <- a) {
ack1!(1)
}|
for (ack2 <- b) {
ack2!("Hello")
}
}
}
#2/14/15:x被赋值为a的Unforgeable Name,y被赋值为b的Unforgeable Name(传入通道)
#4/5:将method1、method2的Unforgeable Name 发送给x、y
#16-20:从a和b中取出method1和method2的Unforgeable Name,然后把某个Process发送给这两个Unforgeable Name,即可触发相应的contract
传出通道中Unforgeable Name的传递
Copyleft © https://rholang-china.org
传入通道和传出通道
在上一段代码中,method1的Unforgeable Name 是怎么传递的?
unforgeable name
x
a
ack1
Copyleft © https://rholang-china.org
传入通道和传出通道
机场控制台把现有的天气和跑道信息存在一个Channel里,然后设置一个控制器,它能够在必要的时候对原始信息进行修改,而飞行员可以查询到相关信息。
例子2:机场控制台
Copyleft © https://rholang-china.org
传入通道和传出通道
传入通道
new stationFactory, stdout(`rho:io:stdout`) in {
contract stationFactory(initialMessage, getInfo, setInfo) = {
new currentMessage in {
currentMessage!(*initialMessage)|
contract setInfo(newMessage) = {
for (msg <- currentMessage) {
currentMessage!(*newMessage)
}
}|
contract getInfo(return) = {
for (msg <- currentMessage) {
return!(*msg)|
currentMessage!(*msg)
}
}
}
}|
new airportInfo, set in {
stationFactory!("Weather is nice", *airportInfo, *set)|
set!("Strong crosswinds, be advised")|
airportInfo!(*stdout)
}
}
例子2:机场控制台
Copyleft © https://rholang-china.org
传入通道和传出通道
设置一个银行账户,可存、可取、可查询。需要注意的是,账户必须保证安全,除了账户所有人之外,其他人不能知道里面的余额,更不能有权限把钱拿出来。
例子3:银行账户
Copyleft © https://rholang-china.org
传入通道和传出通道
new openAccount, stdout(`rho:io:stdout`) in {
// This contract registers a new account and creates its methods.
contract openAccount(initialDeposit, deposit, withdraw, check) = {
new balanceCh in {
balanceCh!(*initialDeposit)|
// Deposit Contract
contract deposit(amount, ack1) = {
for (old <- balanceCh) {
balanceCh!(*old + *amount)|
ack1!(Nil)
}
}|
// Withdraw Contract
contract withdraw(amount, ack2) = {
for (old <- balanceCh) {
balanceCh!(*old - *amount)|
ack2!(Nil)
}
}|
// Check contract
contract check(ack3) = {
for (balance <- balanceCh) {
ack3!(*balance)
}
}
}
}|
// Customer Sarah creates an uses an account
new sarahDeposit, sarahWithdraw, sarahCheck, sarahack in {
openAccount!(10, *sarahDeposit, *sarahWithdraw, *sarahCheck)|
sarahWithdraw!(3, *sarahack)|
for (_ <- sarahack) {
sarahCheck!(*stdout)
}
}
}
#3/#29-30:不同的人在调用主智能合约时,都可以通过新定义属于自己的传入通道来实现账户的安全性
#14/#31:触发withdraw合约,实现账户更新
#10/#17/#32:ack是一个确认channel,作用是:保证在调用check合约时,查询到的是最新的balance。
例子3:银行账户
Copyleft © https://rholang-china.org
传入通道和传出通道
stephanie!(*sarahDeposit)
如果 Sarah想要授权给她的朋友Stephanie向她自己的账户存款的权限(不开放取款和查询余额的功能),她应该执行什么代码?
把Sarah的存款通道传出给Stephanie
例子3:银行账户
Copyleft © https://rholang-china.org
传入通道和传出通道
补充知识点——关于ack
1. ack,acknowledgement 的缩写,是Rholang中常用的、用于确认的Channel
2. 当ack 里面被放入Process时,用来证明:一次相对应的Send 和 Receive(即一次COMM event )已经完成。
3. ack 也可以当做普通的Name来使用
Copyleft © https://rholang-china.org
传入通道和传出通道
new pizzaShop, stdout(`rho:io:stdout`) in {
contract pizzaShop(order, ack) = {
ack!("Order Received.")
}|
new alice in {
pizzaShop!("One medium veggie pizza", *alice)|
for (@info<-alice) {
stdout!(info)
}
}
}
例子4:披萨店订单确认
Alice订购披萨,披萨店在收到订单后向Alice专属的确认Channel内返回“订单已收到”的信息
#2/#6:定义Alice专属的确认Channel,把它的Unforgeable Name 和订单一起传入 contract
pizzashop
#3:订单收到,向确认Channel放入消息
确认Channel——ack
Copyleft © https://rholang-china.org
传入通道和传出通道
确认channel——ack
用作确认channel时,ack 还有一个功能:在Rholang这个以并行为基本逻辑的语言中,实现顺序执行。
Copyleft © https://rholang-china.org
传入通道和传出通道
确认channel——ack
例子5:有顺序的发送
new chan, ack, stdoutAck(`rho:io:stdoutAck`) in {
chan!(0)|
for (_ <- ack) {
chan!(1)
}|
for (@num <= chan) {
stdoutAck!(num, *ack)
}
}
#3-#4:只有把值从ack里取出来,才能触发向chan发送1
#7:stdoutAck的功能是把num收到的值输出到屏幕上,同时在ack里面放入Nil,相当于:stdout!(num) | ack!(Nil)
Copyleft © https://rholang-china.org
传入通道和传出通道
在第二章里,通过Join Operator实现了两个飞行员共同控制火箭的发射。现在,为该情景添加如下功能:
两个人都有权利撤回发射,将命令从“发射”更改到“取消发射”。
例子6:Rocket Launch 升级版
Copyleft © https://rholang-china.org
传入通道和传出通道
new rocketFactory, stdout(`rho:io:stdout`) in {
contract rocketFactory(aliceLaunch, bobLaunch, ackCh) = {
new aliceReadyCh, bobReadyCh in {
contract aliceLaunch(ackAlice) = {
aliceReadyCh!(true)|
new aliceAbort in {
contract aliceAbort(_) = {
for (_ <- aliceReadyCh) {
stdout!("Abort")
}
}|
ackAlice!(*aliceAbort)
}
}|
contract bobLaunch(ackBob) = {
bobReadyCh!(true)|
new bobAbort in {
contract bobAbort(_) = {
for (_ <- bobReadyCh) {
stdout!("Abort")
}
}|
ackBob!(*bobAbort)
}
}|
for (a <- aliceReadyCh; b <- bobReadyCh) {
stdout!("Launch!")|
ackCh!("Launch!")
}
}
}|
// 发射
new aliceLaunch, bobLaunch, ackCh, ackAlice, ackBob in {
rocketFactory!(*aliceLaunch, *bobLaunch, *ackCh)|
aliceLaunch!(*ackAlice)|
bobLaunch!(*ackBob)
}|
// Alice取消发射
new aliceLaunch, bobLaunch, ackCh, ackAlice, ackBob in {
rocketFactory!(*aliceLaunch, *bobLaunch, *ackCh)|
aliceLaunch!(*ackAlice)|
for (x <- ackAlice) {
x!(Nil)
}
}
}
传出通道的使用:#6第一次被触发后,aliceAbort的Unforgeable Name被传出到了ackAlice中,所以,再次触发#6时,相当于向aliceAbort里发送Process,触发contract aliceAbort ,完成“取消发射”的功能
例子6:Rocket Launch 升级版
Copyleft © https://rholang-china.org
传入通道和传出通道
More Cases
例子7:取消/停止触发
new MakeRevokableForwarder in {
contract MakeRevokableForwarder(target, ret) = {
new port, kill, forwardFlag in {
ret!(*port, *kill)|
forwardFlag!(true)|
contract port(msg) = {
for (@status <- forwardFlag) {
forwardFlag!(status)|
match status { true => target!(*msg) }
}
}|
for (_ <- kill; _ <- forwardFlag) {
forwardFlag!(false)
}
}
}|
new target, ret in {
MakeRevokableForwarder!(*target,*ret)|
for (port, kill<- ret) {
port!(111)
// |kill!(000)
}
}
}
传入通道的使用:#17中target和ret的Unforgeable Name 被传入#2
传出通道的使用:#3中port和kill的Unforgeable Name通过ret被传出,所以#20中向port发送Process即可触发#6的contract
触发port的结果:被放入port的msg最后被放入到了target;触发kill的结果,forwardFlag里面被放入false,游戏结束。
Copyleft © https://rholang-china.org
例子8:存衣处
new MakeCoatCheck in {
contract MakeCoatCheck(ret) = {
new port, table in {
ret!(*port)|
for (@"new", @arg, ack <= port) { // 传出通道的使用:port的Unforgeable Name被传出到了ret,#28中又把它取出,之后向cc发送Process即触发相应的合约(#5/11/17)
new ticket in { // 定义一个ticket,代表存衣凭证。它的Unforgeable Name被传出到ack中
ack!(*ticket)|
@{*ticket | *table}!(arg)
}
}|
for (@"get", @arg, ack <= port) { // 查看功能。@"get"用于匹配,@arg代表凭证,ack是返回通道
for (@value <- @{arg | *table}) {
@{arg | *table}!(value)|
ack!(value)
}
}|
for (@"set", @arg1, @arg2, ack <= port) { // 更换存衣功能。@"set"用于匹配,arg1代表凭证,arg2代表新的衣服,ack是返回通道
for (_ <- @{arg1 | *table}) {
@{arg1 | *table}!(arg2)|
ack!(true)
}
}
}
}|
// Usage
new ret, get, set in {
MakeCoatCheck!(*ret)| // 传入通道的使用:ret的Unforgeable Name被传入#2,两个ret等价
for (cc <- ret) {
// Creates new cell with initial value 0
cc!("new", 0, *ret)|
for (ticket <- ret) {
contract get(return) = {
cc!("get", *ticket, *return)
}|
contract set(@value, return) = {
cc!("set", *ticket, value, *return)
}|
get!(*ret)|
for (@r <- ret) {
//r is equal to 0
set!(1, *ret)|
for (_ <- ret) {
get!(*ret)|
for (@r <- ret) {
//r is equal to 1
Nil
}
}
}
}
}
}
}
Copyleft © https://rholang-china.org
More Cases
数据结构
06
Copyleft © https://rholang-china.org
String
1. String是一种组织字符的数据结构,如"hello"
2. String之间用++ 连接
new string, stdout(`rho:io:stdout`) in{
contract string (@word) = {
stdout!("Hello" ++ word)
}|
string!("World")
}
Copyleft © https://rholang-china.org
Tuple
1. Tuple是有顺序的元素集。
2. Tuple! (3, 4, 5),Tuple里面有三个元素;Tuple! ((3, 4, 5)) ,Tuple里面只有一个元素。
new tCh, stdout (`rho:io:stdout`) in {
tCh!!((3, 4, 5))|
for (@t <- tCh){
stdout!(["Test nth. Expected: 5. Got ", t.nth(2)])
}|
for(@t <- tCh){
stdout!(["toByteArray test.Got:",t.toByteArray()])
}
}
(Tuple name).nth(位置)取出tuple中的元素。
例子1: 对Tuple的调用
Tuple的基础知识
Copyleft © https://rholang-china.org
new a,stdout (`rho:io:stdout`) in{
contract a (x,y,z) ={
stdout!("HelloWorld")
}|
a!(1,2,3)|
a!(1)
}
在调用时必须向a send由三个元素组成的Tuple。
例子1: contract定义的name是Tuple
Tuple在contract语句中的应用
Copyleft © https://rholang-china.org
Tuple
建立在Tuple结构上的name,称为compound name。
new alice, bob, key1, key2, stdout(`rho:io:stdout`) in {
alice!(*key1)|
bob!(*key2)|
contract @(*key1, *key2)(_) = {
stdout!("Congratulations, Alice and Bob, you've cooperated.")
}|
for(@a<-alice;@b<-bob){
@(a,b)!(1)
}
}
当alice和bob同时用自己的key调用contract的时候,contract才能被执行。
Tuple在contract语句中的应用
例子2:联合
Copyleft © https://rholang-china.org
Tuple
P | Output |
---|---|
stdout!(t.nth(2)) | Nil |
stdout!(t.toByteArray()) | 2a19aa01160a042a0210020a042a0210040a000a062a041a024869 |
Tuple调用方法一览
Tuple ! ((1,2,Nil,"Hi"))|for(@t<-Tuple){P}
Copyleft © https://rholang-china.org
Tuple
List
List是一个有顺序的数组。
new lCh, stdout(`rho:io:stdout`) in {
lCh!!([3, 4, 5])|
for (@l <- lCh){
stdout!({l.nth(2)})
}|
for (@l <- lCh){
stdout!(["Test slice. Expected: [4, 5]. Got: ", l.slice(1, 3)])
}|
for (@l <- lCh){
stdout!({l.length()})
}
}
例子:对List的调用
List的基础知识
Copyleft © https://rholang-china.org
P | Output |
---|---|
stdout!({l.nth(2)}) | Nil |
stdout!({l.length()}) | 4 |
stdout!({l.slice(1,3)}) | [2,Nil] |
stdout!({l.toByteArray()}) | 2a19a201160a042a0210020a042a0210040a000a062a041a024869 |
List调用方法一览
List ! ([1,2,Nil,"Hi"])|for(@l<-List){P}
Copyleft © https://rholang-china.org
List
Set
Set是一个无序的process的合集,其中每一个元素都是不可重复的。
new sCh, stdout(`rho:io:stdout`) in {
sCh!!(Set(3, 4, 5))|
// 在Set里面加一个process
for (@s <- sCh){
stdout!(["Test add. Expected Set(3, 4, 5, 6), Got: ", s.add(6)])
}|
// 删除Set里面的一个process
for (@s <- sCh){
stdout!(["Test delete. Expected: Set(3, 4). Got: ", s.delete(5)])
}|
for (@s <- sCh){
stdout!(["Test contains. Expected: true. Got:", s.contains(5)])|
stdout!(["Test contains. Expected: false. Got: ", s.contains(6)])
}|
for (@s <- sCh){
stdout!(["Test union. Expected: Set(1, 2, 3, 4, 5). Got: ", s.union(Set(1, 2))])
}|
for (@s <- sCh){
stdout!(["Test diff. Expected: Set(5) Got: ", s.diff(Set(3, 4))])
}|
for (@s <- sCh){
stdout!(["Test toByteArray. Got: ", s.toByteArray()])
}
}
例子:对Set的调用
Set的基础知识
Copyleft © https://rholang-china.org
P | Output |
---|---|
stdout!({s.union(Set(1,4))}) | Set(1,2,4,Nil,"Hi") |
stdout!({s.delete(2)}) | Set(1,Nil,"Hi') |
stdout!({s.contains(5)}) | false |
stdout!({s.size()}) | 4 |
stdout!({s.toByteArray()}) | 2a19b201160a000a042a0210020a042a0210040a062a041a024869 |
Set调用方法一览
Sets! (Set(1,2,Nil,"Hi"))|for(@s<-Sets){P}
Copyleft © https://rholang-china.org
Set
Map
Map的每一个元素都由key和value组成,每个key都不能重复。表现形式为{"a":1,"b":2}。
例子:对Map的调用
new mCh, print(`rho:io:stdout`) in {
mCh!!({"a": 3, "b": 4, "c": 5})|
// .union 用来将两个map联合起来
for (@m <- mCh){
print!(["Test union. Expected: {a: 3, b: 4, c: 5, d: 6}. Got: ", m.union({"d": 6})])
}|
// .diff用来调出map中除了.diff()里面的东西。
for (@m <- mCh){
print!(["Test diff. Expected: {b: 4, c: 5}. Got: ", m.diff({"a": 3})])
}|
for (@m <- mCh){
print!(["Test toByteArray. Got: ", m.toByteArray()])
}|
for (@m <- mCh){
print!(["Test delete. Expected: {a: 3, b: 4}. Got: ", m.delete("c")])
}|
for (@m <- mCh){
print!(["Test contains. Expected: true. Got: ", m.contains("c")])|
print!(["Test contains. Expected: false. Got: ", m.contains("d")])
}|
for (@m <- mCh){
print!(["Test get. Expected: 4. Got: ", m.get("b")])
}|
for (@m <- mCh){
//getOrElse的第二个参数是Default Value
print!(["getOrElseSuccessful. Expected: 4. Got: ", m.getOrElse("b", "?")])|
print!(["getOrElseFailed. Expected: ?. Got: ", m.getOrElse("d", "?")])
}|
for (@m <- mCh){
print!(["Test set. Expected {a: 3, b: 2, c: 5}. Got: ", m.set("b", 2)])
}|
for (@m <- mCh){
print!(["Test keys. Expected Set(a, b, c)). Got: ", m.keys()])
}|
for (@m <- mCh){
print!(["Test size. Expected 3. Got: ", m.size()])
}
}
Map的基础知识
Copyleft © https://rholang-china.org
P | Output |
---|---|
stdout!({m.union{{"c":3}}}) | {"a":1,"b":2,"c":3} |
stdout!({m.delete{"b"}}) | {"a":1} |
stdout({m.contains{"c"}}) | false |
stdout!({m.get{"b"}}) | 2 |
stdout!({m.getOrElse{"d","fail"}}) | fail |
stdout!({m.set{"b",4}}) | {"a":1,"b":4} |
stdout!({m.keys()}) | Set("a","b") |
stdout!({m.size()}) | 2 |
stdout!({m.toByteArray()}) | 2a21ba011e0a0d0a052a031a016112042a0210020a0d0a052a031a016212042a021004 |
Map调用方法一览
Map ! ({"a":1,"b":2})|for(@m<-Map){P}
Copyleft © https://rholang-china.org
Map
调用方法 | 调用目的 | Tuple | List | Map | Set |
---|---|---|---|---|---|
nth | 选取Tuple或list中顺序的某一位 | ✓ | ✓ | ||
toByteArray | 将数据结构以16进制的方式输出 | ✓ | ✓ | ✓ | ✓ |
union | 将两个数据结构合在一起 | ✓ | ✓ | ||
diff | 调出数据结构中除diff()括号内以外的数据 | ✓ | ✓ | ||
add | 在Set中添加一个process | ✓ | |||
delete | 删除key | ✓ | ✓ | ||
contains | 检验map中是否包含某个key | ✓ | ✓ | ||
get | 得到key的value | ✓ | |||
getOrElse | 如果map中没有这个key则输出Default Value | ✓ | |||
set | 更改key的value | ✓ | |||
keys | 调出map中所有key | ✓ | |||
size | map中key的数量 | ✓ | ✓ | ||
length | 输出list中的元素位数 | ✓ | |||
slice | 截取list | ✓ |
数据结构调用方法一览表
Copyleft © https://rholang-china.org
.toByteArray()
数据转换
Rholang里所有数据结构(比如String,Int,List,Map,Set……)都可以转换成字节数组
new stdout(`rho:io:stdout`),sCh,lCh, mCh in {
stdout!(["String","a".toByteArray()])|
stdout!(["Int",16.toByteArray()])|
stdout!(["list",["abc", 100].toByteArray()])|
stdout!(["Set",Set("Hello",1).toByteArray()])|
stdout!(["Map",{"b":99,"bb":999,}.toByteArray()])
}
//运行结果:
//["Int", 2a021020]
//["list", 2a13a201100a072a051a036162630a052a0310c801]
//["Map", 2a24ba01210a0e0a052a031a016212052a0310c6010a0f0a062a041a02626212052a0310ce0f]
//["Set", 2a14b201110a042a0210020a092a071a0548656c6c6f]
//["String", 2a031a0161]
三种加密方法:
keccak256Hash, sha256Hash 和 blake2b256Hash
转换为字节数组后才能加密
数据加密
new stdout(`rho:io:stdout`), hashValueCh in {
@"keccak256Hash"!("1111F8dwxuPdE95j4XVqusbo2dDvkiwgi7JCodF7UQXVFDoWGTrA9".toByteArray(), *hashValueCh)|
for(@hashValue<-hashValueCh){
stdout!(hashValue)
}
}
// 运行结果:7b892e7366cd0f57e846bba7d1f70d6a62acff466e57834b9f70bc08182834e4
new stdout(`rho:io:stdout`), hashValueCh in {
@"sha256Hash"!("1111F8dwxuPdE95j4XVqusbo2dDvkiwgi7JCodF7UQXVFDoWGTrA9".toByteArray(), *hashValueCh)|
for(@hashValue<-hashValueCh){
stdout!(hashValue)
}
}
// 运行结果:ae3d1d0f4cb47251155e707270aa4958dde64278e2cc353937f222fd7345fb80
new stdout(`rho:io:stdout`), hashValueCh in {
@"sha256Hash"!("1111F8dwxuPdE95j4XVqusbo2dDvkiwgi7JCodF7UQXVFDoWGTrA9".toByteArray(), *hashValueCh)|
for(@hashValue<-hashValueCh){
stdout!(hashValue)
}
}
// 运行结果:2f7a32d03369be70d0d1b8f5f42cbb3e241c037fd5b147a9e6f65bca37660ace
匹配
07
Copyleft © https://rholang-china.org
写在前面
在Rholang官方教程中,匹配都叫做"Pattern Matching"。
为了便于理解,在本章节中将"Pattern Matching"分为结构样式匹配和逻辑命题匹配。
Copyleft © https://rholang-china.org
结构样式匹配
Rholang里的结构样式
数据类型 |
---|
Int : -1,12,345 |
Strings : "Hello World" |
Lists : [1,2,"Hi"] |
Booleans : true, false |
Tuples : (1,2,3) |
Sets : Set(a, 5, b) |
Maps : {"a":1, "b":10, "c":100} |
_ |
Copyleft © https://rholang-china.org
语句结构 |
---|
send : a!(b) |
receive : for(x<-a){P} |
Par: P|Q |
Nil |
结构样式匹配
用match进行结构样式匹配
for (@x <- <channel>) {
match x{
pattern1 =>{P}
pattern2 =>{Q}
}
}
- P和X均为Process。
- X是match新定义的Process时,@X 被赋值为P。
- 按顺序从上到下依次匹配,匹配成功则停止。
- _可以匹配一切。通常我们它放在最后,用来表示以上都没有匹配。
match P{
X =>{...}
_ =>{...}
}
当向channel Send Process 符合pattern1时,执行P;符合pattern2时,执行Q。
Copyleft © https://rholang-china.org
new patternMatcher, stdout(`rho:io:stdout`) in {
for (x <= patternMatcher) {
match *x {
Nil => stdout!("Got the stopped process")
"hello" => stdout!("Got the string hello")
[x, y] => stdout!("Got a two-element list")
Int => stdout!("Got an integer")
_ => stdout!("Got something else")
}
}|
patternMatcher!({for(@0 <- @0){0}})|
patternMatcher!({@"world"!("hello")})|
patternMatcher!({Nil|"hello"})|
patternMatcher!({0|"hello"})|
patternMatcher!(Nil)
}
match数据类型匹配
# 13 {Νil|"hello"}={"hello"}
结构样式匹配
用match进行结构样式匹配
Copyleft © https://rholang-china.org
new patternMatcher, stdout(`rho:io:stdout`) in {
for (x <= patternMatcher) {
match *x {
Nil => stdout!("Got the stopped process")
{_!(_)} => stdout!("Got a send")
{for(@0 <- _){_}} => stdout!("Got a receive on @0")
_ => stdout!("Got something else")
}
}|
patternMatcher!({for(@0 <- @0){0}}) |
patternMatcher!({@"world"!("hello")}) |
patternMatcher!({0|"hello"}) |
patternMatcher!(Nil)
}
结构样式匹配
用match进行结构样式匹配
match语句结构匹配
Copyleft © https://rholang-china.org
结构样式匹配
用for进行结构样式匹配
new chan, stdout(`rho:io:stdout`) in {
chan!(1,2,3) |
for (@x, @y, @z <= chan) {
stdout!(["three", x, y, z])
} |
chan!(7,8) |
chan!([9, 10], 11) |
for (@a, @b <= chan) {
stdout!(["two", a, b])
} |
chan!((4,5,6)) |
chan!(12 | 13) |
for (@a <= chan) {
stdout!(["one", a])
}
}
for里的数据类型匹配
- 元素个数和数据类型必须同时匹配才能匹配成功
- {P|Q}既是两个并行的Process,也是一个Process
for (name pattern <- channel) { process }
当向channel send的Process符合name pattern时,上述语句才会被触发
Copyleft © https://rholang-china.org
new chan,stdout(`rho:io:stdout`)in{
for (_ <- chan) {stdout!("Hello")}|
chan!(1|2)|
for (x <- chan) {stdout!("World")}|
chan!(1|2|3)|
for (@{y|x} <- chan) {stdout!("Hi")}|
chan!(333)|
for (@{y|_} <- chan) {stdout!("Hi~")}|
chan!(22|44|66)|
for (@x,@y <- chan) { stdout!(x)}|
chan!(5,10)|
for (@x,_ <- chan) { stdout!(x)}|
chan!(5,10)|
for (@{x!(Q)} <- @"chan") { stdout!(Q)}|
@"chan"!({@"a"!(999)})|
for (@{for (@P <- z) { R }} <- @"chan"){stdout!(R)}|
@"chan"!(for (x <- @"a") {666})
}
for语句结构匹配
结构样式匹配
用for进行结构样式匹配
# 2 # 5 匹配1个Process
# 8 # 11 匹配1个或1个以上并行的Process
# 14 #17 匹配2个Process
# 20 # 23 先进行语句结构匹配,然后赋值
Copyleft © https://rholang-china.org
new chan,stdout(`rho:io:stdout`)in{
for (@{y|Nil} <- chan) {stdout!(y)}|
chan!(Nil|333)|
for (@{for (@5 <- x) {Nil}} <- chan) { stdout!("Hi")}|
chan!(for (@5 <- chan) {Nil})|
for(@{x!("Hello")} <- chan){ stdout!("World")}|
chan!({@"a"!("Hello")})
}
name pattern含有String,Int,触发语句需要与其样式完全一致
for语句结构及数据类型匹配
结构样式匹配
用for进行结构样式匹配
Copyleft © https://rholang-china.org
new chan,stdout(`rho:io:stdout`) in{
contract @(*chan,"method1")(@ack)={stdout!(["method1",ack])}|
@(*chan,"method1")!(1)|
contract @[*chan,"method2"](@ack)={stdout!(["method2",ack])}|
@[*chan,"method2"]!(2)|
contract chan(@"method3",@ack)={stdout!(["method3",ack])}|
chan!("method3",3)|
contract @(*chan,"method4")(@"method4",@ack)={stdout!(["method4",ack])}|
@(*chan,"method4")!("method4",4)
}
结构样式匹配
用contract进行结构样式匹配
contract里的结构样式匹配
- # 3 channel pattern是一个Tuple,Tuple第一个元素为chan的Unforgeable name,第二个元素为"method1"
- # 6 channel pattern是一个List,List第一个元素为chan的Unforgeable name,第二个元素为"method2"
- # 9 name pattern含有两个变量,第一个是@"method3"
contract channel pattern (name pattern) ={ Process }
当channel pattern 和name pattern的都匹配上时,上述语句被触发
Copyleft © https://rholang-china.org
new log(`rho:io:stdout`), missile in {
contract @(*missile, "launch")(_) = {
log!("launching...")
}|
contract @(*missile, "inspect")(_) = {
log!("inspecting...")
}|
contract @"getInspectionChannel"(return) = {
return!((*missile, "inspect"))
}
}
//请补充调用合约,分别实现launch功能,和inspect功能
//|{...}
- #3 #7 两个contract的channel pattern都是Tuple,Tuple第一个元素为missile的Unforgeable name,第二个元素分别为"launch"和"inspect"
- #11-#13 @"getInspectionChennel"是一区块链上的公共name,在#1-#13之外,任何人都能对它进行操作
拿到@(*missile,"inspect")的Unforgeable name的人能触发contract @(*missile,"launch")吗?
如何做到?
结构样式匹配
用contract进行结构样式匹配
火箭发射和监控
Copyleft © https://rholang-china.org
new log(`rho:io:stdout`), missile in {
contract @(*missile, "launch")(_) = {
log!("launching...")
}|
contract @(*missile, "inspect")(_) = {
log!("inspecting...")
}|
contract @"getInspectionChannel"(return) = {
return!((*missile, "inspect"))
}
}
|
new ack in {
@"getInspectionChannel"!(*ack)|
for(@(missile, "inspect") <- ack){
@(missile, "launch")!(Nil)
}
}
#17 通过for匹配,拿到missile的Unforgeable name,进而触发contract @(*missile,"launch")
结构样式匹配
用contract进行结构样式匹配
窃取火箭发射权
Copyleft © https://rholang-china.org
new getInspectionChannel, log(`rho:io:stdout`), missile in {
contract @(*missile, "launch")(_) = {
log!("launching...")
}
|
contract @(*missile, "inspect")(_) = {
log!("inspecting...")
}
|
contract getInspectionChannel(return) = {
return!(bundle+{(*missile, "inspect")})
}
}
#12 bundle+后的(*missile,“inspect”),只能写不能读。
(可以向@(*missile,“inspect”) send process,不能从@(*missile,“inspect”) receive process。详见第九章第一节)
结构样式匹配
用contract进行结构样式匹配
更安全的火箭发射
Copyleft © https://rholang-china.org
逻辑命题 | 判断 |
---|---|
a>b | a大于b时该命题为真 |
a < b | a小于b时该命题为真 |
a == b | a等于b时该命题为真 |
a <= b | a小于等于b时该命题为真 |
a != b | a不等于b时该命题为真 |
a and b, a/\b | 当a和b都为真时,该命题为真 |
a or b, a\/b | 当a或b为真时,该命题为真 |
not a | 当a为假时,该命题为真 |
以上a,b均为Process
逻辑命题匹配
Rholang里的逻辑命题
Copyleft © https://rholang-china.org
new stdout(`rho:io:stdout`) in {
for (@balance <= @"signTest") {
if (balance > 0) {
stdout!("Account in good standing.")
}
else {
stdout!("Account overdrawn.")
}
}
}
|
@"signTest"!(5)
筛选大于0的balance
逻辑命题匹配
if/else逻辑命题匹配
if (cond) {P}
else {Q}
Process cond为真命题时执行P,为假命题时执行Q
Copyleft © https://rholang-china.org
match cond {
true => P
false => Q
}
- Process cond与booleans进行匹配。cond为真命题执行P,cond为假命题执行Q
- cond里只能包含关系运算符,不能包含逻辑运算符
逻辑命题匹配
match逻辑命题匹配
match x {
cond => P
_ => Q
}
方法一
方法二
- x与cond命题等价时,执行P;否则执行Q
if/else是match的语法糖
Copyleft © https://rholang-china.org
算术运算:+, -, *, /
关系运算:>, >=, <, <=, ==, !=
逻辑运算符:and, or, not
new agech,stdout(`rho:io:stdout`) in{
agech!(10)|
agech!(18)|
agech!(20)|
for(@age<=agech){
match {age>=18} {
true =>{stdout!("permission")}
_ =>{stdout!("rejection")}
}
}
}
逻辑命题匹配
match逻辑命题匹配
筛选出年龄大于等于18的人
试试用方法二改写上述代码
参考More Cases
Copyleft © https://rholang-china.org
new log(`rho:io:stdout`), binderChecker in {
contract binderChecker(@data, return) = {
match data {
"nombre" \/ "name" => return!("name-like")
_ => return!("not name-like")
}
}|
binderChecker!("name", *log)|
binderChecker!("nombre", *log)
}
逻辑命题匹配
match逻辑命题匹配
匹配多种字符串
Copyleft © https://rholang-china.org
逻辑命题匹配
for逻辑命题匹配
new StudentGradeLevel, stdout(`rho:io:stdout`) in {
for(@{{@"grade"!(x)}/\{@y!(10)}} <- StudentGradeLevel){stdout!("a")}|
StudentGradeLevel!(@"grade"!(10))
}
用for模拟数据库处理
for (name pattern <- channel) { Process }
- 当name pattern是一个逻辑命题时,触发语句必须向channel Send一个真命题,上述Process才会被触发。
- 目前name pattern里的逻辑连接符只能使用and(/\)
- name pattern不能包含关系运算符。
Copyleft © https://rholang-china.org
new print(`rho:io:stdout`), register in {
for (@{{@"name"!(_) | _} /\ {@"age"!(_) | _}} <= register){
print!("Both name and age were in the data")
}|
register!(@"name"!(Nil))|
register!(@"age"!(Nil))|
register!(@"name"!(Nil) | @"age"!(Nil))|
register!(@"name"!(Nil) | @"age"!(Nil) | @"height"!(175))
}
筛选出数据库中含有@"name" 和@"age"的数据
x被赋值为{@"age"!(_) | y}
逻辑命题匹配
for逻辑命题匹配
Copyleft © https://rholang-china.org
{@"name"!(_) | x} /\ {@"age"!(_) | y}
{x/\{@"age"!(_) | y}}/\{y/\{@"name"!(_) | x}}
=
y被赋值为
{@"name"!(_) | x}
{@"name"!(_)|@"age"!(_) |y}/\{@"age"!(_) |@"name"!(_)|x}
代入
{@"name"!(_)|@"age"!(_) |x}
逻辑命题匹配
contract逻辑命题匹配
new StudentGradeLevel, x, stdout(`rho:io:stdout`) in{
contract StudentGradeLevel (@{{@"grade"!(x)}/\{@y!(10)}}) ={stdout!("a")}|
StudentGradeLevel!(@"grade"!(10))
}
用contract进行数据库处理
contract channel (name pattern) ={ Process }
- 当name pattern是一个逻辑命题时,触发语句必须向channel send一个真命题,上述Process才会被触发
- 目前name pattern里的逻辑命题只能使用and(/\)
Copyleft © https://rholang-china.org
以下样式只能用来做匹配,不能作为Name使用。
- _ => 匹配所有Process
- Int => 匹配所有整数,包括整数和负数
- Bool => 匹配true 和 false
- String => 匹配字符串
- Uri=> 匹配智能合约的ID
- ByteArray=> 匹配所有数据类型的ByteArray
如果要输出1,怎么办?
More Cases
如何进行匹配并赋值
匹配整形
new ack, stdout(`rho:io:stdout`) in {
for (@Int <-ack){
stdout!(Int)
}|
ack!(1)
}
//结果为Nil
Copyleft © https://rholang-china.org
new ack, stdout(`rho:io:stdout`) in {
for (@{x /\ Int} <- ack) {
stdout!(x)
}|
ack!(1)
}
//结果是1
- x/\Int与Int等价,x被赋值为与Int进行匹配的Process
- 首先1与Int匹配,然后1被赋值给x
More Cases
如何进行匹配并赋值
匹配整形并输出
Copyleft © https://rholang-china.org
以下样式只能用来做匹配,不能作为name使用。
- _ => 匹配所有Process
- Int => 匹配所有整数,包括整数和负数
- Bool => 匹配true 和 false
- String => 匹配字符串
- Uri=> 匹配智能合约的ID
- ByteArray=> 匹配所有数据类型的ByteArray
如果要输出uriChan,怎么办?
More Cases
如何进行匹配并赋值
匹配智能合约的ID
new chan, uriChan,insertArbitrary(`rho:registry:insertArbitrary`),stdout(`rho:io:stdout`) in{
insertArbitrary!(bundle+{*chan}, *uriChan)|
for(@{Uri}<-uriChan){
stdout!("success")
}
}
Copyleft © https://rholang-china.org
new chan,stdout(`rho:io:stdout`) in{
chan!(`rho:id:x93d1g1oaj83pn3rgntehae7b3cnxzpktwojrijbg9uk7z8b3hkbw5`)|
for(@{Uri}<-chan){
stdout!("success")
}
}
以下样式只能用来做匹配,不能作为name使用。
- _ => 匹配所有Process
- Int => 匹配所有整数,包括整数和负数
- Bool => 匹配true 和 false
- String => 匹配字符串
- Uri=> 匹配智能合约的ID
- ByteArray=> 匹配所有数据类型的ByteArray
如果要输出ByteArray值,怎么办?
More Cases
如何进行匹配并赋值
匹配所有数据类型的ByteArray
new chan, pm, stdout(`rho:io:stdout`) in{
chan!(123)|
for(@chan_<-chan){
pm!(chan_.toByteArray())|
for(@{ByteArray}<-pm){
stdout!("success")
}
}
}
Copyleft © https://rholang-china.org
new age, stdout(`rho:io:stdout`) in {
for(@{x+5}<- age ){
stdout!(x)
}|
age!({10+5})
}
#5 10+5比{ }优先级高,age 里的Process为15,与{x+5}无法匹配
More Cases
无法匹配的样式
for里的算术运算
Copyleft © https://rholang-china.org
new age, stdout(`rho:io:stdout`) in {
for(@{x>5}<- age ){
stdout!(x)
}|
age!({10>5})
}
#5 10>5比{ }优先级高,age 里的Process为true,与{x>5}无法匹配
for里的关系运算
More Cases
无法匹配的样式
Copyleft © https://rholang-china.org
new age, stdout(`rho:io:stdout`) in {
for(@x<- age ){
match x{
x>5 => stdout!("123")
}
}|
age!(10)
}
#4 x是新定义的Name,与#3的x不同
match里的关系运算
More Cases
无法匹配的样式
Copyleft © https://rholang-china.org
new age, stdout(`rho:io:stdout`) in {
for (@x <- age) {
match x/\10 {
true => stdout!(x)
}
}|
age!(10)
}
#3 报错:不能使用/\
PS: 也不能使用\/
match里的逻辑运算
More Cases
无法匹配的样式
Copyleft © https://rholang-china.org
new helloNameAge, getOlder, stdout(`rho:io:stdout`) in {
contract helloNameAge(@{@"name"!(name) | @"age"!(age) | _}) = {
stdout!(["Hello, ", name, " aged ", age])
} |
contract getOlder(@{rest /\ {@"name"!(_) | _} | @"age"!(age) }, ret) = {
ret!(@"age"!(age + 1) | rest)
} |
getOlder!(@"name"!("Joe") | @"age"!(39), *helloNameAge)
}
例子1: 将数据记录里的年龄+1
- 本案例包含结构样式匹配,逻辑命题匹配
- # 5 是contract的name pattern 匹配,内部包含样式匹配和逻辑命题匹配
- # 2 是contract的name pattern匹配
More Cases
contract里的结构样式&逻辑命题匹配
Copyleft © https://rholang-china.org
例子2: 筛选出age>35岁的人的身份数据
new people, stdout(`rho:io:stdout`) in {
people!(@"name"!("Joe") | @"age"!(20) | @"eyes"!("blue") | @"seq"!(0)) |
people!(@"name"!("Julie") | @"age"!(30) | @"eyes"!("brown") | @"seq"!(0)) |
people!(@"name"!("Jane") | @"age"!(40) | @"eyes"!("green") | @"seq"!(0)) |
people!(@"name"!("Jack") | @"age"!(50) | @"eyes"!("grey") | @"seq"!(0))|
for (@{@"seq"!(0) | {row /\ {@"name"!(name) | @"age"!(age) | _}}} <= people) {
if (age > 35) {
stdout!([name, age])
}|
people!(row | @"seq"!(1))
}
}
More Cases
for里的结构样式&逻辑命题匹配
- #10 信息被放回数据库,并且@“seq”里的值变为1,代表该条身份数据已被读取,且不能再次与#6匹配,避免重复筛选。
- 本案例包含样式匹配,逻辑命题匹配及赋值
Copyleft © https://rholang-china.org
迭代
08
Copyleft © https://rholang-china.org
迭代指智能合约迭代的过程,即反复地运用同一合约计算,前一次迭代得到的结果作为下一次迭代的输入。
迭代
Copyleft © https://rholang-china.org
new myIncrease, stdout(`rho:io:stdout`) in {
new current in {
current!(0)|
contract myIncrease(ack) = {
for (@old <- current) {
current!(old + 1)|
ack!(old)
}
}
}|
new ack in {
myIncrease!(*ack)|
contract ack(@a) = {
if (a <= 5) {
myIncrease!(*ack)|
stdout!(a)
}
}
}
}
例子1:计数器
设置一个可以计数到5,并带有重置功能的计数器。
#4-9 是实现计数功能的智能合约。利用迭代,使#6产生的结果在合约再次被触发后,作为输入条件被#5执行。
#12-18 是触发合约,同样利用迭代,不断触发myIncrease执行,直到不再满足条件后程序停止。
More Cases
Copyleft © https://rholang-china.org
new sum, add, stdout(`rho:io:stdout`) in {
contract sum(@arr, ret) = {
match arr {
[h, ...t] => {
new ack in {
sum!(t, *ack)|
for (@arg <- ack) {
add!(h, arg, *ret)
}
}
}
_ => ret!(0)
}
}|
contract add(@a, @arg, ret) = {
ret!(a + arg)
}|
sum!([4,5,6], *stdout)
}
例子2:计算数组[4,5,6]中各数字的加和
#4 [h, ...t]是一个数组结构,h表示数组中第一位元素,t表示除h之外的其他元素。[h, ...t]用来将数组拆散。
#5-6 将拆出的 t 再次放入sum合约中迭代。注意,每次迭代产生的ack都是新的,用来保证之后的计算按顺序进行。
#7-8 触发#15 add合约,等待计算。
#12 数组为空后,ret中放入0。经过传递,最终0被放入arg中。
#16 ret被放入新的结果,作为输入,再次触发add合约...直到完成计算。
More Cases
Copyleft © https://rholang-china.org
Bundle
09
Copyleft © https://rholang-china.org
Bundle的作用是设置合约调用者的读写权限,共有四种语法:
Syntax | Can Read | Can Write |
---|---|---|
bundle- {proc} | YES | NO |
bundle+ {proc} | NO | YES |
bundle0 {proc} | NO | NO |
bundle {proc} | YES | YES |
Bundle
Copyleft © https://rholang-china.org
如何理解bundle
Bundle对合约调用者的限制,其原理类似于非对称密码学中公私钥的签名和加密。
非对称式密码学是密码学的一种算法,它需要两个密钥:
- 公钥(公开给他人)
- 私钥(不公开,只能由自己秘密保管)
用其中一个加密,用且只能用另一个解密。
虽然两个密钥在数学上相关,但如果知道了其中一个,并不能凭此计算出另外一个。
用法:
- 用公钥对文件加密,只能由自己秘密保管的私钥进行解密,其他人无法读取,故称用公钥加密。
- 用私钥对文件加密,由于私钥只自己持有,其他人无法更改经私钥加密的文件,效果等同于在纸本文件上亲笔签署的效果,所以该过程称为签名。
Copyleft © https://rholang-china.org
只写(bundle+)相当于用公钥加密
如何理解Bundle
Copyleft © https://rholang-china.org
只读(bundle-)就像公钥加密方法中的签名
如何理解bundle
Copyleft © https://rholang-china.org
区块链上的内容是全部可见的,bundle只能解决合约调用时读写权限问题,并不能解决隐私问题。
所以,在使用区块链时需要注意对敏感信息的处理,避免隐私泄露。
如何理解bundle
Copyleft © https://rholang-china.org
例子1:AliceFanMail
Eve想要偷取Alice的邮件,如何防止Eve作恶成功?
Bundle的用法
new alice, stdout(`rho:io:stdout`) in {
new aliceFanMail in {
alice!!(bundle+ {*aliceFanMail})|
for (mail <= aliceFanMail) {
stdout!("Alice received a fanmail")
}
}|
for (aliceFanMail <- alice) {
aliceFanMail!("Dear Alice, you're #TheBest")
}|
for (aliceFanMail <- alice) {
for (@stolenMail <= aliceFanMail) {
stdout!(["Eve stole a message: ", stolenMail])
}
}
}
#3 aliceFanMail被Bundle后传出
#8-10 粉丝接到aliceFanMail后给Alice发信
#11-15 Eve想要偷取Alice的信件,但没成功
Copyleft © https://rholang-china.org
示例2:Jackpot
玩家A扔出一个带有数字的球,其余玩家抢球,抢到球的玩家获得相应分数。如何防止除A以外的人扔球?
new gameCh, stdout(`rho:io:stdout`) in {
new throw in {
gameCh!!(bundle- {*throw})|
throw!(4) |
throw!(2) |
throw!(6)
}|
for (throw <- gameCh) {
for (points <= throw) {
stdout!(["Bill caught it. Points: ", *points])
}
}|
for (throw <- gameCh) {
throw!(100)
}
}
Bundle的用法
#2-7 throw被bundle后开始扔球
#8-12 玩家接球,并报出得分
#13-15 玩家想要作弊,扔出一个分数为100的球,但不成功
Copyleft © https://rholang-china.org
示例3:高阶版Jackpot
玩家扔出1-10共10个数字的球,由另外3个玩家抢球。抢到球的玩家将本轮得分与之前的得分相加并打印出来。
new gameCh, ack, stdout(`rho:io:stdout`) in {
new ret in {
contract gameCh(return) = {
return!(bundle- {*ret})
} |
new throw in {
throw!(1)|
contract throw(@num) = {
if (num <= 10){
throw!(num + 1)|
ret!(num)
}
}
}
}|
new initial in {
new return in {
gameCh!(*return)|
initial!(0)|
for (@throw <- return) {
for (@points <= @throw; @ini <= initial) {
initial!(points + ini)|
stdout!(["P1 get the ball, the sum number is ", points + ini])
}
}
} |
new return in {
gameCh!(*return)|
initial!(0)|
for (@throw <- return) {
for (@points <= @throw; @ini <= initial) {
initial!(points + ini)|
stdout!(["P2 get the ball, the sum number is ", points + ini])
}
}
} |
new return in {
gameCh!(*return)|
initial!(0)|
for (@throw <- return) {
for (@points <= @throw; @ini <= initial) {
initial!(points + ini)|
stdout!(["P3 get the ball, the sum number is ", points + ini])
}
}
}
}
}
#3-4 将ret bundle后传出去。
#6-14 通过迭代的方法实现扔球合约,将结果通过ret传出。
#16-26、#27-36、#37-46 是三个玩家接球并打印结果的合约。
More cases
Copyleft © https://rholang-china.org
Copyleft © https://rholang-china.org
Copyleft © https://rholang-china.org
Powerbox
10
Copyleft © https://rholang-china.org
输出
stderr(`rho:io:stderr`) , stdout(`rho:io:stdout`),
输出到屏幕
new stdout(`rho:io:stdout`), stderr(`rho:io:stderr`) in{
stdout!("Hello")|
stderr!("World")
}
new ackout, ackerr,stdout(`rho:io:stdout`),stderr(`rho:io:stderr`),
stdoutAck(`rho:io:stdoutAck`), stderrAck(`rho:io:stderrAck`) in {
stdoutAck!("hello", *ackout) |
for (@ackout_ <- ackout) {
stdout!([ackout_, "received"])
}|
stderrAck!("world", *ackerr) |
for (@ackerr_ <- ackerr) {
stderr!([ackerr_, "received"])
}
}
stdoutAck(`rho:io:stdoutAck`) , stdout(`rho:io:stdout`),
输出到屏幕,并向指定Channel Send Nil
Copyleft © https://rholang-china.org
获取Block时间
timestamp(`rho:block:timestamp`)
返回的时间为调用timestamp的智能合约propose成功的block time
new timestamp(`rho:block:timestamp`), stdout(`rho:io:stdout`), tCh in {
timestamp!(*tCh) |
for(@t <- tCh) {
match t {
Nil => { stdout!("no block time; no blocks yet? Not connected to Casper network?") }
_ => { stdout!({"block time": t}) }
}
}
}
new alice, uriCh, stdout(`rho:io:stdout`), insertArbitrary(`rho:registry:insertArbitrary`) in {
insertArbitrary!(*alice, *uriCh)|
//insertArbitrary!(bundle+{*alice}, *uriCh)|
//insertArbitrary!(bundle-{*alice}, *uriCh)|
for(uri<-uriCh){
stdout!(["alice",*uri])}
}
//运行结果:["alice", `rho:id:ohgpocjy48frt5cxtoqr8npp1zzy4odm3px67q9tw81ygc3ujm4kd1`]
获取URI
insertArbitrary(`rho:registry:insertArbitrary`)
给一个Unforgeable Name生成URI,拿到URI的人可以对这个Name进行操作。
#3 调用alice的人,只能写不能读
#4 调用alice的人,只能读不能写
Copyleft © https://rholang-china.org
new ack, lookup(`rho:registry:lookup`) in {
lookup!(`rho:id:c8auch5r99u8ffcd3emzhoa9m99x7umrbf43y1jwc85faw8za9ajs9`, *ack)|
for(uriUnforgeableName <- ack){
uriUnforgeableName!(Nil)
}
}
lookup(`rho:registry:lookup`)
通过链上智能合约里某个Unforgeable Name对应的URI 获得对这个Unforgeable Name的操作权限
向URI对应的Unforgeable Name Send 一个Process
new ack, lookup(`rho:registry:lookup`), stdout(`rho:io:stdout`) in {
lookup!(`rho:id:c8auch5r99u8ffcd3emzhoa9m99x7umrbf43y1jwc85faw8za9ajs9`, *ack)|
for(uriUnforgeableName <- ack){
for(@process<-uriUnforgeableName){
stdout!(process)
}
}
}
从URI对应的Unforgeable Name 中Receive一个Process
如果在生成URI时,对该Unforgeable Name进行的bundle-的权限控制,那么调用时,只能Receive,不能Send
通过URI 调用链上智能合约
如果在生成URI时,对该Unforgeable Name进行的bundle+的权限控制,那么调用时,只能Send,不能Receive
Copyleft © https://rholang-china.org
getDeployData(`rho:deploy:params)
new getDeployData(`rho:deploy:params`), ch, stdout(`rho:io:stdout`) in {
getDeployData!(*ch)|
for (_, _, @userId, _ <- ch) {
stdout!(userId)
}
}
//运行结果:048fb9524f276744aab7c765f2aa0b6e1fefdcaff0729b076459434c7f2fd9aa904b73cc711733780e5445c5748e013fdc99d97398ba14a9fa0dda85d3fb9690c9
功能
得到合约部署者的Public Key
用法
必须使用4个参数去receive getDeployData里的值,即#3中for语句左边一定要使用4个变量
除了userId以外,从左到右四个变量以此是:computeCodeHash;phloPrice;timestamp
Copyleft © https://rholang-china.org
生成和验证RevAddress
RevAddress(`rho:rev:address`)
new RevAddress(`rho:rev:address`),revAddressValid,stdout(`rho:io:stdout`) in {
RevAddress!("validate", "1111F8dwxuPdE95j4XVqusbo2dDvkiwgi7JCodF7UQXVFDoWGTrA9", *revAddressValid)|
for (@value <- revAddressValid) {
stdout!({"validate result":value})
}
}
//运行结果:{"validate result" : Nil}
new RevAddress(`rho:rev:address`),revAddrCh,stdout(`rho:io:stdout`) in {
RevAddress!("fromPublicKey",
"0401d0fd5accd56de6d69c1bd4f56d8460485b19908c789085bb3515eac432f7dabc86ea4d43a166a2c49a4eb5882b4e72b01dad32e493fbe5cfe2150779235758"
.hexToBytes(), *revAddrCh) |
for (@revAddress <- revAddrCh) {
stdout!({"revAddress":revAddress})
}
}
//运行结果:{"revAddress" : "1111F8dwxuPdE95j4XVqusbo2dDvkiwgi7JCodF7UQXVFDoWGTrA9"}
"fromPublicKey"功能,传入publickey,返回对应的RevAddress
"validate"功能,传入RevAddress,如果RevAddress是存在的,则验证成功返回Nil ,否则不返回Process
About
感谢 Mike Stay 和 Joshy Orndorff的英文Rholang教程
本教程编辑团队来自 歪脑袋矿池(WeNode.io):
Rholang-China 招募RChain及Rholang的爱好者加入生态建设 https://rholang-china.org/
加RChain官方微信群
请加BlockChainForever001
拉你入群
Dimworm
愁虫
Ziqi
Lango
Iris
今夕何年
Nancy
柳菇凉
Rholang 中文教程 v1.0
By 愁虫Dimworm
Rholang 中文教程 v1.0
Rholang China 社区出品
- 5,176