纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

通过示例学习rholang(上部:课程0-6)

RChain中国   2020-01-30 我要评论

通过例子和实践来学习rho语言下面的例子和练习都很值得去运行、阅读、修改和完善修改练习和教程中任何你感到有意思的代码这样能够获得最好的学习效果该教程包含了rho语言最常见以及最重要的特性足以让开发者快速入门

课程0 -- 开发环境

配置你的开发环境

为了可以运行这个教程里面的rholang代码你需要一些开发环境 这不是一个会让你感到疲惫的rholang开发工具或者技术栈 然而它展示了一些基本的开发环境给你开始

网上编译器

RChain社区的成员提供了一个基于公共网站的在线rholang编译器 这个工具非常有前途也是一种入门的简单方式 但是它还是开发节点有时候会不稳定

本地节点

真正正确运行rholang代码的方法是在通过启动你自己本地机子的RNode然后使用它的rholang编译器 首先你要为你自己的平台安装 RNode

对于初学者这里有详细的一步一步指导你怎么使用AWS 或者Docker启动你的节点.

一旦你的RNode安装好了你可以运行基本的独立节点

$ rnode run -s -n

在单独的终端里你可以在REPL模式下一次执行一行rholang

$ rnode repl

╦═╗┌─┐┬ ┬┌─┐┬┌┐┌ ╔╗╔┌─┐┌┬┐┌─┐ ╦═╗╔═╗╔═╗╦
╠╦╝│ ├─┤├─┤││││ ║║║│ │ ││├┤ ╠╦╝║╣ ╠═╝║
╩╚═└─┘┴ ┴┴ ┴┴┘└┘ ╝╚╝└─┘─┴┘└─┘ ╩╚═╚═╝╩ ╩═╝

rholang $ Nil

Deployment cost: CostAccount(0,Cost(0))

Storage Contents:

for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }

rholang $ @"world"!("hello")

Deployment cost: CostAccount(5,Cost(64))

Storage Contents:

@{"world"}!("hello") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }

当你运行更多行数的rholang代码时候你可以使用RNode的eval模式来执行代码

$ rnode eval intersection.rho

Evaluating from intersection.rho

Result for intersection.rho:

Deployment cost: CostAccount(39,Cost(1132))

Storage Contents:

@{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)}!(@{"name"}!(Nil)) | @{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)}!(@{"age"}!(Nil)) | @{"world"}!("hello") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( @{{@{"name"}!() | _ /\ @{"age"}!() | _}} <= @{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)} ) { @{Unforgeable(0x00)}!("Both name and age were in the data") } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }

有一些RNode的输出会出现在你运行代码的同一个终端但是其它一些代码输出会直接出现在第一个终端 所以在你熟悉什么输出出现在哪里前请确定好检查两边的终端

Cryptofex IDE

一个叫做cryptofex 的开发环境已经进入了alpha版本 Cryptofex可能最后最好的开发rholang的地方但是现在还是很早期的软件 Cryptofex提供rholang语法高亮特性并且可以在RChain集成节点上检测dApps IDE同时也提供环境创建和测试在以太网上私人测试网上和单独模式的EVM上的智能合约

课程1 -- 发送与标准输出(stdout)

发送与标准输出(stdout)

说声Hello

 

"Person waiving hello"

 

编程界有一个存在已久的传统——输出"Hello World"应该是你学习的第一个程序下面是一个在屏幕上输出"Hello World"的最简单例子

hello.rho

练习

请让程序输出"Rholang rocks!" 而不是 "Hello World"

练习

尝试将"stdout"替换为别的语句会得到什么结果?

尝试一下这个有趣的通道名称@"someChannel". 这里可以比较随意请让程序在屏幕上输出 "Sup World"

标准输出(stdout)到底是什么东西

 

 

Channels are like mailboxes for sending messages

rho语言的核心是通道(channel,下面都称为通道)通信. 通道是你可以用来发送和接收消息的通信线路你可以使用!字符来在通道中发送消息

 

 

Redo this diagram!

stdout 是一个特殊的通道用于将文本发送至"标准输出",通常指你的电脑屏幕正因为它的特殊我们不得不将它写在第一段学习的代码里面

使用其他通道

 

 

Sent messages wait to be received here in "message purgatory"... JK, it's called the "tuplespace"

实际上你可以在很多通道中发送消息而非只有stdout 但其它通道不像 stdout 他们不会在屏幕上显示

tupleSpace.rho

那么在其他通道中的消息将被发送至哪里?哪里都不会去!这些消息暂时哪儿都不去这些消息会继续待在通道内等待其他人去取出它们我们将在下一课程中学习如何获取这些消息同时消息滞留所在的地方我们称为 "元组空间"

请确保你的信息保留在元组空间里你应该会看到像下面的信息

Storage Contents:

@{"RandoChannel"}!("This won't be on the screen") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }

同时做两件事

 

 

Rather than following an ordered list, all ingredients are added concurrently. Looks delicions

在rholang中我们不会告诉计算机做完一件事再到另一件相反我们会告诉它需要做的所有事情然后"并行地"执行它们或者一次性全部执行

parallel.rho

| 的发音是 "parallel", 可简称为 "par"

练习

向"pizza shop"通道发送消息"1 large pepperoni please"

练习

向"Mom's Phone"通道发送"Hi Mom"

练习

用一个程序在屏幕上输出两个消息"Rick"和 "Morty"

小测试

stdout!("Programming!") 将在屏幕上输出什么?

Programming!

stdout!

Nothing

@"what"!("Up") 在什么通道上发送消息?

@"Up"

@"what"

what

rholang会先执行哪一条语句?

@"stdout"!("Dogs")

|

@"stdout"!("Cats")

输出 "Dogs"

输出 "Cats"

都不 它们是并行的 PS. 有一个特殊的通道 stderr. 请尝试一下看看往这个通道发送消息会发生什么? 有什么区别?

课程2 -- 接收

消息检查

 

// Dear future self, keys in freezer because...

在上一章我们学习了如何发送消息现在是时候学习如何接收消息了常规语法如下:

for(message <- channel){ // Do something here}

顺便提一下 // 用于标示注释 //后面的内容程序并不会运行写好注释可以有利于其他开发者(包括你自己)阅读代码并了解代码的意图其他读你代码的开发者会感激你写注释的

通信事件

 

 

Pizza shop can receive messages on its channel.

下面的代码使用披萨店的通道发送了一个消息披萨店收到了它pizza店通过将消息打印至标准输出来表明其已收到

pizzaOrder

练习

将上述消息发送至一个不同的通道如@"coffeShop". 消息会被接收端打印出来吗? 还是东西留在了元组空间里么?

 

Let's hit up the coffee shop.

练习

记住在rholang中任何事情都是并行地而非按顺序地执行如果我们把接收信息的代码放在前面那么披萨店的代码仍可执行尝试一下吧

元组空间污染

如果你遇到了旧数据滞留在元组空间并会对后面的代码执行有影响你需要清空你的元组空间最简单的方式是删除你的数据目录.rnode

使用上述方法清空元组空间已经过时了一个更好的方法是防止它一开始被旧数据污染我们可以通过修改最上面的new代码段来实现

旧的方案

new stdout(rho:io:stdout) in { @"world"!("Welcome to RChain") }

尝试下面新的方案

new world, stdout(rho:io:stdout) in { world!("Welcome to RChain") // No more @ or " " }

我们将在“不可伪造的names”的课程中讲解它的原理现在你不需要每次都重置通道

发送前接收

 

 

Rather than the message appearing first, then someone receiving it, Greg is trying to receive first. Hopefully someone will send him a message so he can have a comm event.

当发送和接收同时存在于通道时这被称为通信事件或称为"comm event"

不像普通邮件那样必须被发送对方才能被接收在rholang中上述两个事件可以以任何顺序发生或者同时发生这类似于可以先接收消息再发送它每当发送和接收共存时就会触发通信事件

合约

 

 

The poor chef is too busy making sure he can receive orders to take care of his pizza.

我们的披萨店例子很好地说明了通信事件但期望每次有新的订单时披萨店都能自动发出一个新的接收来处理它们这并不现实

幸运地是我们可以只部署一次代码然后每次接收到它的消息时都执行一次这类代码称为“智能合约”让我们看一个比披萨店更高级但相似的例子--咖啡店

coffeeShop.rho

练习

在咖啡店点第二杯饮料

练习

更改上面例子的确认消息

一般来说下列哪一个会第一个发生?

发送因为它与普通邮件的工作原理一样 接收因为以该方式运行的代码更快 发送或接收都可以最先发生或者同时 接收因为rohlang是并行的 都不直接触发通信事件(comm event)

练习

通道被命名为 @"coffeeShop"将它更名为你所选择的特定咖啡店的名称然后使用我们最近学到的new来修改代码

Persistent For

实际上在rholang中有两种不同的语法来表示持续从通道取出信息我们刚刚学习contract语法下面的用for语法的代码是等价的

contract @"coffeeShop"(order) = { for(order <= @"coffeeShop") { 注意上述代码与正常的 for 不同因为它使用了双划线 <= 而不是单划线 <-. for和contract是有不同的地方的我们会在讨论区块链的时候讨论到他们的区别现在你可以将它们当做同一功能

练习

用持久的for语法而不是"contract"语法来写一个想咖啡店这样的披萨店合约尝试自己从头写一次整个代码这样会让你更容易记清语法

下面哪一项是与其他两项不同的?

for (a <- b){}

contract b(a) = {}

for (a <= b){}

哪一个发送语句会与for (message <- @"grandmasSnapChat"){Nil}对应产生一个通信事件 ?

grandmasSnapChat!("Hi Grandma")

@"grandmasSnapChat"!("Glad you're snapping Grandma")

for("Here's a snap for you g'ma" <- @"grandmasSnapChat")

课程3 -- 传音筒、"name"和“process”

消息传递

 


The game of telephone is perfect to simulate message forwarding in rholang.

在前面的章节我们学习了如何向祖母或披萨店发送消息但是至今所有的接收方都通过将消息打印至标准输出来告知已经接收到了

现在让我们做一些更有意思的事情--类似孩子们的传话游戏那样传递消息

telephone3.rho

你可以通过运行上面的代码来做实验你可以修改你觉得合适的地方多运行几次

练习

传话游戏很有趣但有更多玩家参与会更好请添加第三位明教Charlie的玩家bob接收消息后将发送消息给Charlie而不是简单打印至stdout然后Charlie将它打印至屏幕上多多益善!

 

 

The message never seems to get there correctly. I blame Bob.

练习

如果你曾经玩过电话游戏你应该知道消息极少能被正确地传递Bob现在决定通过发送一条错误的消息改写程序使得Bob无论收到什么都能传递不同的消息

*这到底是啥?

 


Opposites attract

你注意到 @"Bob"!(message)中的? 在rholang中有两种类型 "names" 和 "processes"同样也有可以在两者之间互相转化的方法

"processes"可以是rholang中任何一个代码片段例如我们的传话筒游戏或者是披萨店订单程序“process”可以是上百行的大程序也可以只有几行它们甚至可以是用于表示值的代码下面是一些“process”的例子

stdout!("Sup Rholang?") 一个常见的发送操作

Nil 最小的“process”如字面意思它不做任何事

for(msg <- @"phone"){Nil} 一个常见的接收操作在消息到达时它不会做任何事

"Hello World" 另一个不做任何事请的小“process”被称为"基础术语" "names"可以被用于赋名通道以发送消息在大多数编程语言中"name"是完全独立的一样东西它们本身就存在但是在rholang中"name"来自"引用process"即将@标签放在“process”之前即可得到一个"name"下面是"name"的一些例子

@"Hello World" 通过引用基础术语"Hello World"来创建

@Nil 最小的“name”通过引用最小的“process”来创建

@(@"Alice"!("I like rholang, pass it on."))

通过引用来自传话筒游戏的"process"来创建

关于*的一切

 


What kind of name is that!? Did your parents just name you after some computer code?

通过用@符号来标记“process”我们可以将“process”打包以创建一些“name”我们也可以通过使用*标记“name”从而将“name”转变为“process”

在rholang中我们需要记住的是发送“process”和接收“name”这很重要因此我再次强调你总是发送一个“process”在另一端接收一个“name”

Aice通过for(message <- @"Alice")接收我们的消息所以 message 变成了一个“name”当她之后发送给Bob时她不得不发送“process”所以她要用@"Bob"!(message)使用将message转变回一个“process”

小测验

我们发送什么?

processes

names

我们接收什么?

processes

names

@"registration"是什么?

process

name

非法语法

Nil是什么?

process

name

非法语法

@Nil是什么?

process

name

非法语法

@@Nil是什么?

process

name

非法语法

*importantData 是一个“process”, 那么importantData是什么?

process

name

非法语法

下面哪一个与"BobsPhone"等价?

*@"BobsPhone"

@"BobsPhone"

*"BobsPhone"

@*BobsPhone

stdout!("BobsPhone")

练习

 


This telephone game has a fork

不像之前的线性传话游戏那样每个玩家将信息传递给下一位我么来为游戏添加一个分支现在Bob与先前一样将发送消息给Charlie但同时也会发送给Elise

每个分支的长度由你定但在每个分支的最后都得将消息打印至标准输出

课程4 -- 持续发送与窥探

 


 

为什么要重复发送?

This radio navigation aid helps airplanes navigate by broadcasting the same message over and over

我们的披萨和咖啡店都可以在同一个复用通道中接收消息我们使用一个持续的for (msg <= chan){...}或者一个合约contract chan(msg){...}来达成这一目的

空中交通管制塔楼可能会乐于做刚好相反的事——不停地发送相同的消息塔楼中的控制者希望记录同时包含天气和跑道信息的消息并且提供给所有需要的飞行员类似披萨店 他们很繁忙不会费力地在每次飞行员需要时都不停地发送信息

持续发送的语法

控制塔需要在代码上做较小的调整以使得发送操作能够持续他们会使用!!而非单个!

persistentSend.rho

请自行确认一下原先发送的消息是否仍然在元组空间内

练习

注意上述代码第二名飞行员同样能够接收到信息发送仍在持续

对了你注意到了吗?当我们实际上并不使用stdout时我们不需要new stdout(...) in {}

for (x <- y) {Nil} | y!!(Nil)中有多少次通信事件发生?

1

很多次

0

二次检查消息

正如我们刚才展示的持续性发送和接收非常有用但是普通的发送和接收也同样足够好了设想这样的场景:我将一个字母发送给祖母她接收到了这个消息

grandma.rho

现在我们设想:我想要二次检查我是否给她发送了正确的时间我可以简单地取出这条消息但这样一来她就没法读取这个消息了

练习

依据你所知道的你可以通过获取这个消息自行检查它再将它发送回旧的通道以达到我们的目的

请自行尝试上面的方案答案已列在下面

for (x <= y) {Nil} | y!!(Nil)会产生多少个通信事件?

1

很多个

0

答案

grandmaCheck.rho

窥探语法

Maybe I'll just peak at Grandma's letter through the envelope.

rholang以后会为观察通道内变量提供一个特殊的语法目前我们还不能使用它但是下面会展示给你看这个语法的用法我们将使用<!操作符来"窥探"一个通道内的消息

peek.rho

如果你使用过excel的宏或者excel你应该对如何在不取出数据的情况下访问它感到非常熟悉把它当做for (value <! A1) { ... }

下列哪一个语法是用于窥探一个消息的?

for (x <! y){...}

for (x <= y){...}

x!!(y)

for (x <! y) {Nil} | y!!(Nil)会产生多少个通信事件?

1

许多

0

课程5 -- Join操作

多数据源

 


In general, the winner of this pushup competition can't be determined until both participants are finished.

有时候仅当从两个以上不同的数据源获取数据后才会开始计算例如在你得知了你的彩票号码和中奖号码之前你无法知道你是否赢得大奖在你知道购买物品价格和购买总额之前你无法进行购买在你知道每个参赛者做了多少个俯卧撑前你无法知道谁赢得俯卧撑比赛

rholang提供了Join操作来应对这种情况使用;符号来执行一次Join操作

for (p1Pushups <- @"player1"; p2Pushups <- @"player2") { @"stdout"!("The winner is...") }

火箭发射

一家太空探索公司想要确保仅当两个航空工程师Alice和Bob都下达了发射命令后他们的火箭才会发射例如Bob将通过发送BobLaunch!("launch")来下达命令当两位工程师都下达了命令那么火箭便可以发射

练习

思考一下使用我们刚提到的Join操作符应该怎么写这个代码呢?

错误的方式

下面的例子中其中一人先收到发射指令并尝试处理火箭发射问题然后再轮到另一个人

launchBad.rho

问题在于当Alice批准发射而Bob还没有Alice应该能够更改她的指令但在此例中她不行设想一下如果她突然发觉火箭有一个问题或者收到了一些不好的消息想要停止发射

 

 

No use in grabbing just one set of mail. Might as well wait until the second set

当使用Join时她依然可以更改她的决定因为for只会在双方的消息都进入通道并准备好后才会开始取出双方的消息

发射的解决方案

launch.rho

下列哪一段代码是Alice所需用以撤销发射命令的?

@"AliceCancel"!("cancelZ")

@"AliceLaunch"!("cancel")

for (x <- @"AliceLaunch"){Nil}

Join的概念起初是在哲学家进餐问题中被提出并且在这篇简短的rholang教程中(更详细的解释)[developer.rchain.coop/tutorial/#d…"]

在for (x <- y; a <- b){ Nil }中, 应该优先向哪一个通道发送消息?

y

b

无所谓

同时被发送

在for (x <- y; a <- b){ Nil }中, 哪一条消息被优先取出?

x

a

无所谓

会被同时取出

练习

有一个比赛两名选手将各自在各自的通道发送消息谁第一个发送了消息谁就输掉比 赛第二个发送消息的人获胜你的任务是写一段代码告诉我们谁赢了参赛选手应按如下方式发送消息

P1!("Send any message") P2!("Hope I win")

在这场需要靠耐心获胜竞赛这一例子中我们不使用求并运算因为我们在意哪个选手先行动希望你没有陷入我的陷阱中;)

patienceSolution.rho

正如注释所说你应该使用REPL模式运行上面的代码然后用两种不同的顺序来发送的消息确保两个选手都获胜一次另一个方案如下所示让一个玩家去通知另一个玩家何时执行我们将在下一节继续研究这种方法

P1First.rho

在上面我们写的代码中为什么可能出现没有人赢得这场耐心比赛?

因为两名选手可以同时发送消息

选手们在错误的通道发送消息

第一个块接收P2而第二个块接收P1所以代码并不能保证游戏完成

课程6 -- 不可伪造的Names和Acks

使通道"私有"

 

 

A competing pizza shop steals orders because the channel isn't secure.

到目前为止每一个我们发送信息的通道都是公共的"name"如@"pizzaShop" 任何一个人都可以往这个通道发送信息(可能对于某些商用行为是好的)但是任何一个人也可以从这个通道中获取信息(这对于一些商业就很糟糕了)想象一下如果竞争者可以从披萨店中获取他们的披萨订单让披萨店无法获取他们的订单那肯定十分糟糕

披萨店的竞争者需要什么样的代码来窃取披萨点的订单?

contract evilPizzaShop(interceptedMessage) = {Nil}

@"evilPizzaShop"!("pizzaShop")

@"pizzaShop"!("intercept")

for (interceptedMessage <- @"pizzaShop"){...}

绑定和自由的Names

上面我们学习到如何通过for和contract获取信息这两种方式都构造出"绑定的"“names”举个下面例子order就是在咖啡店代码里一个绑定的"name"

bound1.rho

当我们使用contract语法的时候也是一样的

bound2.rho

如果一个"name"存在在一个特定的"process"中并且不能被"process"外部访问我们就认为一个"name"是绑定的所以"name" order是绑定在咖啡代码中另一方面在上面的例子中任何一个能从别的地方访问的"name"都是"自由的"“name”在上面的例子中@"coffeeShop" 是一个自由的"name"

指出下面每段代码中 x 是绑定的还是自由的

for (x <- y){Nil}

绑定的

自由的

都不是

for (y <- x){Nil}

绑定的

自由的

都不是

new x in { x!(true) }

绑定的

自由的

都不是

contract x(y) = { Nil }

绑定的

自由的

都不是

contract y(x) = { Nil }

绑定的

自由的

都不是

for (y <- @"x"){Nil}

绑定的

自由的

都不是

new操作符

for 和 contract都是在连续计算中绑定"name"的完美方法但是如果我们想要创建一个绑定的"name"用于发送? 举个例子我们的披萨店不想让自己的订单被人截取我们通过new操作符解决这个问题

newPizzaShop.rho

首先要注意到 pizzaShop 是一个"name"即使它不是以 @开始

那是因为new操作符直接把它创造为一个"name"而不是一个引号括起的"process"无论你如何使用new创造一个"name", 它总是一个绑定的"name"

然后注意这种方法不仅可以阻止其它披萨店获取订单还阻止新的客户下订单我们将会在bundles教程中解决这个问题

当你在new 限制范围外尝试下订单会发生什么事情

订单正常发送

订单正常发送但是需要更长时间

出现关于顶层自由变量的错误

代码可以运行但是没有订单成功被接受不了

我们学习到所有的"name"可以通过用@标记转化为"process"所以 pizzaShop这个"name"通过@转化后是一个什么样的"process"? 尝试将那个"process"打印到stdout 看看

@标记的"pizzaShop"

并没有任何标记

"一些不可以伪造的16进制代码"

私有 vs 不可伪造

 

 

Although the messages can no longer be stolen, they can still be eavesdropped on. You've been warned.

new 是一个限制操作符因为它把自己创建的绑定的"names"限制在它的花扩话中或者说"词法范围"内. 在rholang的世界里这些新建的"names"就只能在确定的范围内可见但是记住程序员可以从外部世界中查找到这些"names"当你在区块链环境工作中尤其要注意

所以说虽然竞争的披萨店不再可能窃取 本来给我们店的披萨订单但是他们仍然可以在区块链浏览器中知道我们这些订单的信息有些情况下一些程序员会把new 创建的"names"称为 "私有的", 但是一个更恰当的词应该是 "不可伪造的(unforgeable)", 这就能解释前面的问题了

我们前面用到了 new 来阻止元组空间被污染. 为什么使用不可伪造的"names"可以让我们避免每个合约跑之前都清理一次元组空间?

因为 new 创建自由的"names"

因为 new 创建出不可伪造的"names",它们不能被外部代码使用

因为 new 自动清理元组空间

确认通道

 

 

We acknowledge communications all the time in conversations

不可伪造"names"一个通用的用法就是 "确认通道", 简称为"ack" 通道. 披萨店可以仅仅让顾客知道订单已经被下达而不是通过打印到屏幕让每一个人都知道来确认订单

为了能实现这个方法披萨点需要知道如何联系客户所以客户需要提供一个确认通道来回调通常这样的通道被称为ack.

pizzaAck.rho

为什么前面例子的确认信息并没有显示在屏幕上?

代码中有错误

订单没有正确被接收

确认信息没有发送到stdout

练习

之前的例子会导致元组空间中的@"Alice" 和 @"Bob"通道被污染.修改它让Alice 和 Bob 各自有自己的不可伪造的"name".

给发送的"names"权限

我们刚刚看到顾客如何给出一个ack通道来获取订单确定信息. 其实我们可以做得更好. 在我们之前的代码,任何一个人都可以在ack通道中联系客户. 那意味着任何一个人都可以发送一个伪造的ack通道给客户让客户认为订单已经下发成功但是实际上并没有所以Alice 和 Bob 真的需要严格保管他们的不可伪造的"names". 因为给别人那个"name"就意味着别人可以联系你

privateAck.rho

解决方案是创建一个新的不可伪造的"name",然后发送它到披萨店以至于只有他们可以回复你即使披萨店是在new alice的外面, 它仍然可以在那个通道上发送信息因为Alice给了通道名字这是一个很好的方法来委派权限

在这个例子中我们相信披萨店只会在ack通道中 发送 但是要注意它也又可能是在通道中接收信息如果它想要的话我们将在下一节bundles中学习如何只给出一部分的权限出来

Bob也想要订一份披萨给出一个不可伪造的ack通道我们应该在哪里创建他自己的不可伪造的通道?

在他自己的那行,alice代码后面

在Alice同一行

在程序代码的第一行

stdoutAck 和 stderrAck

现在既然你知道了ack通道, 那么你应该要知道其它两种打印到屏幕的方法.它们是叫做stdoutAck 和 stderrAck的通道. 他们就像第一课说的stdout一样工作但是他们需要一个ack通道

stdoutAck.rho

顺便说一句你注意到每次启动一个新的元组空间都有一堆东西么?这些东西其中4个东西是内置的用于接受屏幕打印的通道另外一些是用于加密的我们将在以后讨论到

练习

stdout!("1")|stdout!("2")|stdout!("3")

注意这段程序不会按照一定的顺序打印出数字他们是同时发生的想象我们现在真的要按照顺序打印几行修改代码使用ack通道来保证数字按顺序打印出来

练习

预测这个程序怎么运行(它会输出什么它在元组空间怎么简化计算)然后运行它来检测你的预测

new myChan in { myChan!("Hi There") } | for (msg <- myChan) {stdout!(*msg)}

如果你对上面的程序预测失败修改程序让程序按照你的想法运行

提问

在 for(x <- y){Nil}中哪个name是绑定的

x

y

Nil

在 new x in {Nil}哪个"name"是绑定的

x

y

Nil

如果 pizzzaShop 是一个"name", 那么 @pizzaShop是什么?

一个name

一个process

无效的语法

为什么pizzaShopAck 代码发送 "bob" 作为一个ack通道而不是@"bob"?

没有原因; 就是一种风格

因为 @"bob" 是一个name, 但是我们必须发送processed

那是给ack通道用的特别语法


相关文章

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式