RChain运行原理[2] - 元组空间(Tuplespace)

本文介绍Rholang中的消息传递机制,包括基础的channel操作及合约的使用方法。通过示例展示了如何利用合约实现对消息的响应,并介绍了元组空间的概念及其对程序可组合性的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rholang的消息机制与元组空间

1. 消息机制

在上一篇《初识Rholang》中提到了Rholang通信机制的两个基本操作:

  • for( x <- channel ) Pchannel这个name中读取一条消息并删除,消息保存到x这个name中后执行P
  • channel!(Q)Q这个process发送到channel这个name中

Rholang的name(quoted process)用于收发消息,所以有时候也称name(quoted process)为channel。

这里可以将一个name视为一个信箱,如下。
这里写图片描述

它的工作方式如下:

  • 信箱取件的顺序并不保证和存入顺序一致。
  • for( x <- channel ) P表示从channel这个“信箱”取件后继续执行PP在这里表示一个process,这个process在取件后调用,因此称为continuation。
    特别需要注意的是,如果在取件时信箱为空,调用者并不会等待。相反,调用者将P这条指令存入到该信箱中。
  • 同样,在执行channel!(Q)往信箱中放入Q时,会首先检查信箱中是否有continuation。如果有的话,并不需要将Q存入信箱中,只需将continuation取出后之间与Q匹配继续执行。
  • 因此,信箱中保存的即有可能是continuation P, 也可能是Q

2. 合约

有如下代码:

new helloWorld in {
  for( x <- helloWorld ){
     @"stdout"!(*x)
  } 
}

按照上面的解释可以理解为:在helloWorld这个信箱中放入指令{ @"stdout"!(*x) }等待消息到达后执行。
如果向该信箱存入两条消息,比如helloWorld!("Hi") | helloWorld!("你好"),执行结果如下:

这里写图片描述

可以看到,<-监听后的continuation只会执行一次,这段代码要么输出"Hi", 要么输出"你好"

如果将上面的代码稍作修改,将<-改为<=,结果会如何?

for( x <= helloWorld ){
    @"stdout"!(*x)
} 

<=操作符和<-类似。唯一的不同在于在执行完continuation后,该continuation指令并不会从信箱中删除。

这里写图片描述

因此,可以看到,使用<=监听的continuation每次有消息到达都会执行,有多少次消息到达就会执行多少次。

实际上这段<=的代码还有另一种写法:

contract helloWorld(x) = {
    @"stdout"!(*x)
}

换用contract关键字后,代码执行结果与<=并无差异。

这里写图片描述

比较上面的两张截图可以看到,contract<=两段代码EVALUATING的结果完全一样,这说明contract就是等价于<=的语法糖。

那么contract关键字定义的就是一个合约。所谓合约,即一段绑定到某个name的指令,这段指令在每次有消息到达时都会执行

3. 一个稍微复杂点的例子

3.1 首先申明 addtotalget三个name。

new add, total, get in {
}

可以将它们看成三个信箱,现在它们的状态都是空的。
这里写图片描述

3.2 然后在add这个信箱中部署合约

contract add(@num) = {
    if (num > 0) {
      for( @current <- total ) {
          total!(num+current)
      }
    }
  }

现在add这个信箱中就放入了该合约的指令,该指令的含义为:如果接受到的是一个正数,则将total信箱中的数字取出然后加上该正数的结果存回total信箱。
这里写图片描述

3.3 给total信箱设置初始值

total!(0)

total信箱中现在就有了数字零了。

这里写图片描述

3.4 监听get信箱

for( rtn <- get ) {
    for( @current <- total ) {
      rtn!(current) |
      total!(current)
    }
}

现在get信箱为空,因此它现在也存入了一条指令。这条指令含义是:如果有name被投递到该信箱,则将total中的值取出后发送给该name;同时也发送给total恢复它的状态。

这里写图片描述

3.5 向add信箱发送数字3

add!(3)

执行该语句会触发add信箱中的合约指令,执行完该语句后,total信箱中保存的数字变为了3

这里写图片描述

3.6 向add信箱发送数字5

add!(5)

执行该语句会触发add信箱中的合约指令,执行完该语句后,total信箱中保存的数字变为了8

这里写图片描述

3.7 声明一个新的name

new return in {
}

这里写图片描述

3.8 将该name发送给get信箱

get!(*return)

执行该语句会触发get信箱的指令,执行完后,get中的指令删除了,而return信箱中有了数字8

这里写图片描述

3.9 完整代码

下面是完整代码,可以将它复制到https://rchain.cloud/执行。

new add, total, get in {
  contract add(@num) = {
    if (num > 0) {
      for( @current <- total ) {
          total!(num+current)
      }
    }
  } |
  for( rtn <- get ) {
    for( @current <- total ) {
      rtn!(current) |
      total!(current)
    }
  } |
  total!(0) |
  add!(3) |
  add!(4) |
  new return in {
     get!(*return) |
     for( @v <- return ) {
         @"stdout"!(v)
     }
  }
}

这里由于|是并行执行的,对get的调用相对于其它并行执行的process的顺序并不是固定的,所以如果你多试几次的话,每次得到的结果可能会不同。

4. 元组空间(Tuplespace)与可组合性(Compositionality)

从上面的例子可以看到

  • Rholang的代码与数据合为一体,都存在于name中。
  • Rholang代码的执行的最终结果即是name的状态变化。

这些name的集合即是元组空间(tuplespace),可以将它们想象成一组信箱、或者一个快递柜。

这里写图片描述

因此,Rholang在RChain上的执行的本质是元组空间的状态变迁

假设有两台计算机,每台计算机上都维护了一个元组空间。
如果addget这两个name由其中一台计算机负责维护,另外两个name由另一台计算机维护,即使它们来自于不同的tuplespace,但是对于代码的逻辑是没有任何影响的。
这也是RhoCalculus与传统的冯洛伊曼计算机最大的不同 - 可组合性(Compositionality)

可组合性的意思是说,一台基于RhoCalculus的计算机和另一台基于RhoCalculus的计算机能够组成一个新的基于RhoCalculus的计算机。

这里写图片描述

而这对于程序本身是透明的!RChain通过可以无限叠加的RhoMachine来组成一个计算网络,而这个计算网络整体上就是一个大的RhoMachine!这就是RChain无限可扩展性的根源!

本文地址: https://blog.youkuaiyun.com/wangjia184/article/details/80277759 转载须注明出处

下一篇《名字空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值