通過示例學(xué)習(xí)rholang(上部:課程0-6)

通過例子和實(shí)踐來學(xué)習(xí)rho語言。下面的例子和練習(xí)都很值得去運(yùn)行、閱讀、修改和完善。修改練習(xí)和教程中任何你感到有意思的代碼,這樣能夠獲得最好的學(xué)習(xí)效果。該教程包含了rho語言最常見以及最重要的特性,足以讓開發(fā)者快速入門。

課程0 -- 開發(fā)環(huán)境

配置你的開發(fā)環(huán)境

為了可以運(yùn)行這個教程里面的rholang代碼,你需要一些開發(fā)環(huán)境。 這不是一個會讓你感到疲憊的rholang開發(fā)工具或者技術(shù)棧。 然而它展示了一些基本的開發(fā)環(huán)境給你開始。

網(wǎng)上編譯器

RChain社區(qū)的成員提供了一個基于公共網(wǎng)站的在線rholang編譯器。 這個工具非常有前途,也是一種入門的簡單方式。 但是它還是開發(fā)節(jié)點(diǎn),有時候會不穩(wěn)定。

本地節(jié)點(diǎn)

真正正確運(yùn)行rholang代碼的方法是在通過啟動你自己本地機(jī)子的RNode然后使用它的rholang編譯器。 首先你要為你自己的平臺安裝 RNode

對于初學(xué)者,這里有詳細(xì)的一步一步指導(dǎo)你怎么使用AWS 或者Docker啟動你的節(jié)點(diǎn).

一旦你的RNode安裝好了,你可以運(yùn)行基本的獨(dú)立節(jié)點(diǎn)。

$ rnode run -s -n

在單獨(dú)的終端里,你可以在REPL模式下一次執(zhí)行一行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 }

當(dāng)你運(yùn)行更多行數(shù)的rholang代碼時候,你可以使用RNode的eval模式來執(zhí)行代碼。

$ 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的輸出會出現(xiàn)在你運(yùn)行代碼的同一個終端。但是其它一些代碼輸出會直接出現(xiàn)在第一個終端。 所以在你熟悉什么輸出出現(xiàn)在哪里前請確定好檢查兩邊的終端。

Cryptofex IDE

一個叫做cryptofex 的開發(fā)環(huán)境已經(jīng)進(jìn)入了alpha版本。 Cryptofex可能最后最好的開發(fā)rholang的地方,但是現(xiàn)在還是很早期的軟件。 Cryptofex提供rholang語法高亮特性并且可以在RChain集成節(jié)點(diǎn)上檢測dApps。 IDE同時也提供環(huán)境創(chuàng)建和測試在以太網(wǎng)上,私人測試網(wǎng)上和單獨(dú)模式的EVM上的智能合約。

課程1 -- 發(fā)送與標(biāo)準(zhǔn)輸出(stdout)

發(fā)送與標(biāo)準(zhǔn)輸出(stdout)

說聲Hello


"Person waiving hello"


編程界有一個存在已久的傳統(tǒng)——輸出"Hello World"應(yīng)該是你學(xué)習(xí)的第一個程序。下面是一個在屏幕上輸出"Hello World"的最簡單例子。

hello.rho

練習(xí)

請讓程序輸出"Rholang rocks!" 而不是 "Hello World"。

練習(xí)

嘗試將"stdout"替換為別的語句。會得到什么結(jié)果?

嘗試一下這個有趣的通道名稱@"someChannel". 這里可以比較隨意。請讓程序在屏幕上輸出 "Sup World"。

標(biāo)準(zhǔn)輸出(stdout)到底是什么東西



Channels are like mailboxes for sending messages

rho語言的核心是通道(channel,下面都稱為通道)通信. 通道是你可以用來發(fā)送和接收消息的通信線路。你可以使用!字符來在通道中發(fā)送消息。



Redo this diagram!

stdout 是一個特殊的通道,用于將文本發(fā)送至"標(biāo)準(zhǔn)輸出",通常指你的電腦屏幕。正因?yàn)樗奶厥?,我們不得不將它寫在第一段學(xué)習(xí)的代碼里面。

使用其他通道



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

實(shí)際上你可以在很多通道中發(fā)送消息,而非只有stdout。 但其它通道不像 stdout 他們不會在屏幕上顯示。

tupleSpace.rho

那么,在其他通道中的消息將被發(fā)送至哪里?哪里都不會去!這些消息暫時哪兒都不去,這些消息會繼續(xù)待在通道內(nèi),等待其他人去取出它們。我們將在下一課程中學(xué)習(xí)如何獲取這些消息。同時,消息滯留所在的地方,我們稱為 "元組空間"。

請確保你的信息保留在元組空間里。你應(yīng)該會看到像下面的信息。

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中,我們不會告訴計算機(jī)做完一件事,再到另一件。相反,我們會告訴它需要做的所有事情,然后"并行地"執(zhí)行它們,或者一次性全部執(zhí)行。

parallel.rho

| 的發(fā)音是 "parallel", 可簡稱為 "par"。

練習(xí)

向"pizza shop"通道發(fā)送消息"1 large pepperoni please"。

練習(xí)

向"Mom's Phone"通道發(fā)送"Hi Mom"。

練習(xí)

用一個程序在屏幕上輸出兩個消息,"Rick"和 "Morty"。

小測試

stdout!("Programming!") 將在屏幕上輸出什么?

Programming!

stdout!

Nothing

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

@"Up"

@"what"

what

rholang會先執(zhí)行哪一條語句?

@"stdout"!("Dogs")

|

@"stdout"!("Cats")

輸出 "Dogs"

輸出 "Cats"

都不。 它們是并行的 PS. 有一個特殊的通道 stderr. 請嘗試一下看看往這個通道發(fā)送消息,會發(fā)生什么? 有什么區(qū)別?

課程2 -- 接收

消息檢查


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

在上一章我們學(xué)習(xí)了如何發(fā)送消息?,F(xiàn)在是時候?qū)W習(xí)如何接收消息了。常規(guī)語法如下:

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

順便提一下, // 用于標(biāo)示注釋。 //后面的內(nèi)容程序并不會運(yùn)行。寫好注釋可以有利于其他開發(fā)者(包括你自己)閱讀代碼,并了解代碼的意圖,其他讀你代碼的開發(fā)者會感激你寫注釋的。

通信事件



Pizza shop can receive messages on its channel.

下面的代碼使用披薩店的通道發(fā)送了一個消息,披薩店收到了它。pizza店通過將消息打印至標(biāo)準(zhǔn)輸出來表明其已收到。

pizzaOrder

練習(xí)

將上述消息發(fā)送至一個不同的通道,如@"coffeShop". 消息會被接收端打印出來嗎? 還是東西留在了元組空間里么?

Let's hit up the coffee shop.

練習(xí)

記住,在rholang中,任何事情都是并行地而非按順序地執(zhí)行。如果我們把接收信息的代碼放在前面,那么披薩店的代碼仍可執(zhí)行。嘗試一下吧。

元組空間污染

如果你遇到了舊數(shù)據(jù)滯留在元組空間并會對后面的代碼執(zhí)行有影響,你需要清空你的元組空間。最簡單的方式是刪除你的數(shù)據(jù)目錄.rnode

使用上述方法清空元組空間已經(jīng)過時了。一個更好的方法是防止它一開始被舊數(shù)據(jù)污染。我們可以通過修改最上面的new代碼段來實(shí)現(xiàn)。

舊的方案

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”的課程中講解它的原理?,F(xiàn)在你不需要每次都重置通道。

發(fā)送前接收



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.

當(dāng)發(fā)送和接收同時存在于通道時,這被稱為通信事件,或稱為"comm event"。

不像普通郵件那樣必須被發(fā)送,對方才能被接收,在rholang中,上述兩個事件可以以任何順序發(fā)生或者同時發(fā)生。這類似于可以先接收消息,再發(fā)送它。每當(dāng)發(fā)送和接收共存時,就會觸發(fā)通信事件。

合約



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

我們的披薩店例子很好地說明了通信事件,但期望每次有新的訂單時,披薩店都能自動發(fā)出一個新的接收來處理它們,這并不現(xiàn)實(shí)。

幸運(yùn)地是,我們可以只部署一次代碼,然后每次接收到它的消息時都執(zhí)行一次。這類代碼稱為“智能合約”。讓我們看一個比披薩店更高級但相似的例子--咖啡店。

coffeeShop.rho

練習(xí)

在咖啡店點(diǎn)第二杯飲料

練習(xí)

更改上面例子的確認(rèn)消息

一般來說,下列哪一個會第一個發(fā)生?

發(fā)送,因?yàn)樗c普通郵件的工作原理一樣。 接收,因?yàn)橐栽摲绞竭\(yùn)行的代碼更快。 發(fā)送或接收都可以最先發(fā)生,或者同時。 接收,因?yàn)閞ohlang是并行的。 都不。直接觸發(fā)通信事件(comm event)。

練習(xí)

通道被命名為 @"coffeeShop"。將它更名為你所選擇的特定咖啡店的名稱。然后使用我們最近學(xué)到的new來修改代碼

Persistent For

實(shí)際上,在rholang中有兩種不同的語法來表示持續(xù)從通道取出信息。我們剛剛學(xué)習(xí)contract語法。下面的用for語法的代碼是等價的。

contract @"coffeeShop"(order) = { for(order <= @"coffeeShop") { 注意,上述代碼與正常的 for 不同,因?yàn)樗褂昧穗p劃線 <= 而不是單劃線 <-. for和contract是有不同的地方的,我們會在討論區(qū)塊鏈的時候討論到他們的區(qū)別?,F(xiàn)在你可以將它們當(dāng)做同一功能。

練習(xí)

用持久的for語法而不是"contract"語法來寫一個想咖啡店這樣的披薩店合約。嘗試自己從頭寫一次整個代碼,這樣會讓你更容易記清語法。

下面哪一項是與其他兩項不同的?

for (a <- b){}

contract b(a) = {}

for (a <= b){}

哪一個發(fā)送語句會與for (message <- @"grandmasSnapChat"){Nil}對應(yīng)產(chǎn)生一個通信事件 ?

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.

在前面的章節(jié),我們學(xué)習(xí)了如何向祖母或披薩店發(fā)送消息。但是至今所有的接收方都通過將消息打印至標(biāo)準(zhǔn)輸出,來告知已經(jīng)接收到了。

現(xiàn)在讓我們做一些更有意思的事情--類似孩子們的傳話游戲那樣傳遞消息。

telephone3.rho

你可以通過運(yùn)行上面的代碼來做實(shí)驗(yàn)。你可以修改你覺得合適的地方多運(yùn)行幾次。

練習(xí)

傳話游戲很有趣,但有更多玩家參與會更好。請?zhí)砑拥谌幻鹘藽harlie的玩家。bob接收消息后將發(fā)送消息給Charlie,而不是簡單打印至stdout。然后Charlie將它打印至屏幕上。多多益善!


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

練習(xí)

如果你曾經(jīng)玩過電話游戲,你應(yīng)該知道,消息極少能被正確地傳遞。Bob現(xiàn)在決定通過發(fā)送一條錯誤的消息。改寫程序,使得Bob無論收到什么,都能傳遞不同的消息。

*這到底是啥?

Opposites attract

你注意到 @"Bob"!(message)中的? 在rholang中有兩種類型, "names" 和 "processes"。同樣也有可以在兩者之間互相轉(zhuǎn)化的方法。

"processes"可以是rholang中任何一個代碼片段,例如我們的傳話筒游戲,或者是披薩店訂單程序。“process”可以是上百行的大程序,也可以只有幾行。它們甚至可以是用于表示值的代碼。下面是一些“process”的例子。

stdout!("Sup Rholang?") 一個常見的發(fā)送操作。

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

for(msg <- @"phone"){Nil} 一個常見的接收操作,在消息到達(dá)時它不會做任何事。

"Hello World" 另一個不做任何事請的小“process”。被稱為"基礎(chǔ)術(shù)語"。 "names"可以被用于賦名通道以發(fā)送消息。在大多數(shù)編程語言中,"name"是完全獨(dú)立的一樣?xùn)|西,它們本身就存在。但是在rholang中,"name"來自"引用process",即將@標(biāo)簽放在“process”之前,即可得到一個"name"。下面是"name"的一些例子。

@"Hello World" 通過引用基礎(chǔ)術(shù)語"Hello World"來創(chuàng)建。

@Nil 最小的“name”。通過引用最小的“process”來創(chuàng)建。

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

通過引用來自傳話筒游戲的"process"來創(chuàng)建。

關(guān)于*的一切

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

通過用@符號來標(biāo)記“process”,我們可以將“process”打包以創(chuàng)建一些“name”。我們也可以通過使用*標(biāo)記“name”,從而將“name”轉(zhuǎn)變?yōu)椤皃rocess”。

在rholang中,我們需要記住的是發(fā)送“process”和接收“name”。這很重要,因此我再次強(qiáng)調(diào)。你總是發(fā)送一個“process”,在另一端接收一個“name”。

Aice通過for(message <- @"Alice")接收我們的消息,所以, message 變成了一個“name”。當(dāng)她之后發(fā)送給Bob時,她不得不發(fā)送“process”,所以她要用@"Bob"!(message)使用將message轉(zhuǎn)變回一個“process”。

小測驗(yàn)

我們發(fā)送什么?

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")

練習(xí)

This telephone game has a fork

不像之前的線性傳話游戲那樣,每個玩家將信息傳遞給下一位,我么來為游戲添加一個分支?,F(xiàn)在,Bob與先前一樣將發(fā)送消息給Charlie,但同時也會發(fā)送給Elise。

每個分支的長度由你定,但在每個分支的最后都得將消息打印至標(biāo)準(zhǔn)輸出。

課程4 -- 持續(xù)發(fā)送與窺探


為什么要重復(fù)發(fā)送?

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

我們的披薩和咖啡店都可以在同一個復(fù)用通道中接收消息。我們使用一個持續(xù)的for (msg <= chan){...}或者一個合約contract chan(msg){...}來達(dá)成這一目的。

空中交通管制塔樓可能會樂于做剛好相反的事——不停地發(fā)送相同的消息。塔樓中的控制者希望記錄同時包含天氣和跑道信息的消息,并且提供給所有需要的飛行員。類似披薩店, 他們很繁忙,不會費(fèi)力地在每次飛行員需要時都不停地發(fā)送信息。

持續(xù)發(fā)送的語法

控制塔需要在代碼上做較小的調(diào)整,以使得發(fā)送操作能夠持續(xù)。他們會使用!!而非單個!。

persistentSend.rho

請自行確認(rèn)一下,原先發(fā)送的消息是否仍然在元組空間內(nèi)。

練習(xí)

注意上述代碼,第二名飛行員同樣能夠接收到信息。發(fā)送仍在持續(xù)。

對了,你注意到了嗎?當(dāng)我們實(shí)際上并不使用stdout時,我們不需要new stdout(...) in {}

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

1

很多次

0

二次檢查消息

正如我們剛才展示的,持續(xù)性發(fā)送和接收非常有用。但是,普通的發(fā)送和接收也同樣足夠好了。設(shè)想這樣的場景:我將一個字母發(fā)送給祖母,她接收到了這個消息。

grandma.rho

現(xiàn)在我們設(shè)想:我想要二次檢查我是否給她發(fā)送了正確的時間。我可以簡單地取出這條消息,但這樣一來她就沒法讀取這個消息了。

練習(xí)

依據(jù)你所知道的,你可以通過獲取這個消息,自行檢查它,再將它發(fā)送回舊的通道,以達(dá)到我們的目的。

請自行嘗試上面的方案。答案已列在下面。

for (x <= y) {Nil} | y!!(Nil)會產(chǎn)生多少個通信事件?

1

很多個

0

答案

grandmaCheck.rho

窺探語法

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

rholang以后會為觀察通道內(nèi)變量提供一個特殊的語法。目前我們還不能使用它,但是下面會展示給你看這個語法的用法。我們將使用<!操作符來"窺探"一個通道內(nèi)的消息。

peek.rho

如果你使用過excel的宏,或者excel,你應(yīng)該對如何在不取出數(shù)據(jù)的情況下訪問它感到非常熟悉。把它當(dāng)做for (value <! A1) { ... }。

下列哪一個語法是用于窺探一個消息的?

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

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

x!!(y)

for (x <! y) {Nil} | y!!(Nil)會產(chǎn)生多少個通信事件?

1

許多

0

課程5 -- Join操作

多數(shù)據(jù)源

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

有時候僅當(dāng)從兩個以上不同的數(shù)據(jù)源獲取數(shù)據(jù)后,才會開始計算。例如,在你得知了你的彩票號碼和中獎號碼之前,你無法知道你是否贏得大獎。在你知道購買物品價格和購買總額之前,你無法進(jìn)行購買。在你知道每個參賽者做了多少個俯臥撐前,你無法知道誰贏得俯臥撐比賽。

rholang提供了Join操作,來應(yīng)對這種情況。使用;符號來執(zhí)行一次Join操作。

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

火箭發(fā)射

一家太空探索公司想要確保,僅當(dāng)兩個航空工程師,Alice和Bob,都下達(dá)了發(fā)射命令后,他們的火箭才會發(fā)射。例如,Bob將通過發(fā)送BobLaunch!("launch")來下達(dá)命令。當(dāng)兩位工程師都下達(dá)了命令,那么火箭便可以發(fā)射。

練習(xí)

思考一下,使用我們剛提到的Join操作符,應(yīng)該怎么寫這個代碼呢?

錯誤的方式

下面的例子中,其中一人先收到發(fā)射指令,并嘗試處理火箭發(fā)射問題,然后再輪到另一個人。

launchBad.rho

問題在于,當(dāng)Alice批準(zhǔn)發(fā)射,而Bob還沒有,Alice應(yīng)該能夠更改她的指令,但在此例中她不行。設(shè)想一下,如果她突然發(fā)覺火箭有一個問題,或者收到了一些不好的消息,想要停止發(fā)射。


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

當(dāng)使用Join時,她依然可以更改她的決定,因?yàn)閒or只會在雙方的消息都進(jìn)入通道并準(zhǔn)備好后,才會開始取出雙方的消息。

發(fā)射的解決方案

launch.rho

下列哪一段代碼是Alice所需,用以撤銷發(fā)射命令的?

@"AliceCancel"!("cancelZ")

@"AliceLaunch"!("cancel")

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

Join的概念起初是在哲學(xué)家進(jìn)餐問題中被提出,并且在這篇簡短的rholang教程中(更詳細(xì)的解釋)[developer.rchain.coop/tutorial/#d…"]。

在for (x <- y; a <- b){ Nil }中, 應(yīng)該優(yōu)先向哪一個通道發(fā)送消息?

y

b

無所謂

同時被發(fā)送

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

x

a

無所謂

會被同時取出

練習(xí)

有一個比賽,兩名選手將各自在各自的通道發(fā)送消息。誰第一個發(fā)送了消息,誰就輸?shù)舯?賽,第二個發(fā)送消息的人獲勝。你的任務(wù)是寫一段代碼告訴我們誰贏了。參賽選手應(yīng)按如下方式發(fā)送消息。

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

在這場需要靠耐心獲勝競賽這一例子中,我們不使用求并運(yùn)算,因?yàn)槲覀冊谝饽膫€選手先行動。希望你沒有陷入我的陷阱中;)

patienceSolution.rho

正如注釋所說,你應(yīng)該使用REPL模式運(yùn)行上面的代碼,然后用兩種不同的順序來發(fā)送的消息確保兩個選手都獲勝一次。另一個方案如下所示,讓一個玩家去通知另一個玩家何時執(zhí)行。我們將在下一節(jié)繼續(xù)研究這種方法。

P1First.rho

在上面我們寫的代碼中,為什么可能出現(xiàn)沒有人贏得這場耐心比賽?

因?yàn)閮擅x手可以同時發(fā)送消息

選手們在錯誤的通道發(fā)送消息

第一個塊接收P2,而第二個塊接收P1,所以代碼并不能保證游戲完成

課程6 -- 不可偽造的Names和Acks

使通道"私有"



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

到目前為止,每一個我們發(fā)送信息的通道都是公共的"name",如@"pizzaShop"。 任何一個人都可以往這個通道發(fā)送信息(可能對于某些商用行為是好的),但是任何一個人也可以從這個通道中獲取信息(這對于一些商業(yè)就很糟糕了)。想象一下如果競爭者可以從披薩店中獲取他們的披薩訂單讓披薩店無法獲取他們的訂單,那肯定十分糟糕。

披薩店的競爭者需要什么樣的代碼來竊取披薩點(diǎn)的訂單?

contract evilPizzaShop(interceptedMessage) = {Nil}

@"evilPizzaShop"!("pizzaShop")

@"pizzaShop"!("intercept")

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

綁定和自由的Names

上面我們學(xué)習(xí)到如何通過for和contract獲取信息。這兩種方式都構(gòu)造出"綁定的"“names”。舉個下面例子,order就是在咖啡店代碼里一個綁定的"name"。

bound1.rho

當(dāng)我們使用contract語法的時候也是一樣的。

bound2.rho

如果一個"name"存在在一個特定的"process"中并且不能被"process"外部訪問,我們就認(rèn)為一個"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都是在連續(xù)計算中綁定"name"的完美方法。但是如果我們想要創(chuàng)建一個綁定的"name"用于發(fā)送? 舉個例子,我們的披薩店不想讓自己的訂單被人截取。我們通過new操作符解決這個問題。

newPizzaShop.rho

首先要注意到 pizzaShop 是一個"name"即使它不是以 @開始。

那是因?yàn)閚ew操作符直接把它創(chuàng)造為一個"name"而不是一個引號括起的"process"。無論你如何使用new創(chuàng)造一個"name", 它總是一個綁定的"name"。

然后,注意這種方法不僅可以阻止其它披薩店獲取訂單,還阻止新的客戶下訂單。我們將會在bundles教程中解決這個問題。

當(dāng)你在new 限制范圍外嘗試下訂單會發(fā)生什么事情。

訂單正常發(fā)送

訂單正常發(fā)送但是需要更長時間

出現(xiàn)關(guān)于頂層自由變量的錯誤

代碼可以運(yùn)行,但是沒有訂單成功被接受不了

我們學(xué)習(xí)到所有的"name"可以通過用@標(biāo)記轉(zhuǎn)化為"process"。所以 pizzaShop這個"name"通過@轉(zhuǎn)化后是一個什么樣的"process"? 嘗試將那個"process"打印到stdout 看看。

@標(biāo)記的"pizzaShop"

并沒有任何標(biāo)記

"一些不可以偽造的16進(jìn)制代碼"

私有 vs 不可偽造



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

new 是一個限制操作符因?yàn)樗炎约簞?chuàng)建的綁定的"names"限制在它的花擴(kuò)話中或者說"詞法范圍"內(nèi). 在rholang的世界里,這些新建的"names"就只能在確定的范圍內(nèi)可見,但是記住,程序員可以從外部世界中查找到這些"names"。當(dāng)你在區(qū)塊鏈環(huán)境工作中尤其要注意。

所以說,雖然競爭的披薩店不再可能竊取 本來給我們店的披薩訂單,但是他們?nèi)匀豢梢栽趨^(qū)塊鏈瀏覽器中知道我們這些訂單的信息。有些情況下,一些程序員會把new 創(chuàng)建的"names"稱為 "私有的", 但是一個更恰當(dāng)?shù)脑~應(yīng)該是 "不可偽造的(unforgeable)", 這就能解釋前面的問題了。

我們前面用到了 new 來阻止元組空間被污染. 為什么使用不可偽造的"names"可以讓我們避免每個合約跑之前都清理一次元組空間?

因?yàn)?new 創(chuàng)建自由的"names"

因?yàn)?new 創(chuàng)建出不可偽造的"names",它們不能被外部代碼使用

因?yàn)?new 自動清理元組空間

確認(rèn)通道



We acknowledge communications all the time in conversations

不可偽造"names"一個通用的用法就是 "確認(rèn)通道", 簡稱為"ack" 通道. 披薩店可以僅僅讓顧客知道訂單已經(jīng)被下達(dá),而不是通過打印到屏幕讓每一個人都知道來確認(rèn)訂單。

為了能實(shí)現(xiàn)這個方法,披薩點(diǎn)需要知道如何聯(lián)系客戶。所以客戶需要提供一個確認(rèn)通道來回調(diào)。通常這樣的通道被稱為ack.

pizzaAck.rho

為什么前面例子的確認(rèn)信息并沒有顯示在屏幕上?

代碼中有錯誤

訂單沒有正確被接收

確認(rèn)信息沒有發(fā)送到stdout

練習(xí)

之前的例子會導(dǎo)致元組空間中的@"Alice" 和 @"Bob"通道被污染.修改它,讓Alice 和 Bob 各自有自己的不可偽造的"name".

給發(fā)送的"names"權(quán)限

我們剛剛看到顧客如何給出一個ack通道來獲取訂單確定信息. 其實(shí)我們可以做得更好. 在我們之前的代碼,任何一個人都可以在ack通道中聯(lián)系客戶. 那意味著任何一個人都可以發(fā)送一個偽造的ack通道給客戶讓客戶認(rèn)為訂單已經(jīng)下發(fā)成功,但是實(shí)際上并沒有。所以Alice 和 Bob 真的需要嚴(yán)格保管他們的不可偽造的"names". 因?yàn)榻o別人那個"name"就意味著別人可以聯(lián)系你。

privateAck.rho

解決方案是創(chuàng)建一個新的不可偽造的"name",然后發(fā)送它到披薩店以至于只有他們可以回復(fù)你。即使披薩店是在new alice的外面, 它仍然可以在那個通道上發(fā)送信息因?yàn)锳lice給了通道名字。這是一個很好的方法來委派權(quán)限。

在這個例子中,我們相信披薩店只會在ack通道中 發(fā)送 ,但是要注意它也又可能是在通道中接收信息,如果它想要的話。我們將在下一節(jié)bundles中學(xué)習(xí)如何只給出一部分的權(quán)限出來。

Bob也想要訂一份披薩,給出一個不可偽造的ack通道。我們應(yīng)該在哪里創(chuàng)建他自己的不可偽造的通道?

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

在Alice同一行

在程序代碼的第一行

stdoutAck 和 stderrAck

現(xiàn)在既然你知道了ack通道, 那么你應(yīng)該要知道其它兩種打印到屏幕的方法.它們是叫做stdoutAck 和 stderrAck的通道. 他們就像第一課說的stdout一樣工作,但是他們需要一個ack通道。

stdoutAck.rho

順便說一句,你注意到每次啟動一個新的元組空間都有一堆東西么?這些東西其中4個東西是內(nèi)置的用于接受屏幕打印的通道。另外一些是用于加密的。我們將在以后討論到。

練習(xí)

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

注意這段程序不會按照一定的順序打印出數(shù)字。他們是同時發(fā)生的。想象我們現(xiàn)在真的要按照順序打印幾行。修改代碼,使用ack通道來保證數(shù)字按順序打印出來。

練習(xí)

預(yù)測這個程序怎么運(yùn)行(它會輸出什么,它在元組空間怎么簡化計算。)然后運(yùn)行它來檢測你的預(yù)測。

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

如果你對上面的程序預(yù)測失敗,修改程序,讓程序按照你的想法運(yùn)行。

提問

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

x

y

Nil

在 new x in {Nil}哪個"name"是綁定的

x

y

Nil

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

一個name

一個process

無效的語法

為什么pizzaShopAck 代碼發(fā)送 "bob" 作為一個ack通道而不是@"bob"?

沒有原因; 就是一種風(fēng)格。

因?yàn)?@"bob" 是一個name, 但是我們必須發(fā)送processed。

那是給ack通道用的特別語法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容