├── .gitignore ├── 00-DeveloperEnvironment ├── README.md ├── README_CN.md └── README_RU.md ├── 01-SendingAndStandardOut ├── README.md ├── README_CN.md ├── README_RU.md ├── cooking.png ├── hello.rho ├── helloWorld.png ├── mailbox.png ├── mailboxes.png ├── parallel.rho ├── sendSyntax.png └── tupleSpace.rho ├── 02-Receiving ├── Keys.png ├── README.md ├── README_CN.md ├── README_RU.md ├── coffee.png ├── coffeeShop.rho ├── lookingForMessages.png ├── persistentPizzaShop.rho ├── pizza.png ├── pizzaBurning.png └── pizzaOrder.rho ├── 03-TelephoneNamesAndProcesses ├── README.md ├── README_CN.md ├── README_RU.md ├── inverse.png ├── myNameIs.png ├── telephone.png ├── telephone3.rho ├── telephoneChangedMessage.png └── telephoneFork.png ├── 04-PersistentSendAndPeek ├── README.md ├── README_CN.md ├── README_RU.md ├── broadcasting.png ├── grandmaCheck.rho ├── letterPeek.png ├── peek.rho ├── persistentSend.rho ├── putBack.rho └── putBackAnswer.rho ├── 05-JoinOperator ├── P1First.rho ├── README.md ├── README_CN.md ├── README_RU.md ├── join.png ├── launch.rho ├── launchBad.rho ├── patienceSolution.rho └── pushups.png ├── 06-UnforgeableNamesAndAcks ├── README.md ├── README_CN.md ├── README_RU.md ├── bound1.rho ├── bound2.rho ├── eavesdropping.png ├── newPizzaShop.rho ├── pizzaAck.rho ├── privateAck.rho ├── roger.png ├── stdoutAck.rho └── stealing.png ├── 07-BundlesAndInterpolation ├── Alice.png ├── README.md ├── README_CN.md ├── fanmailAsk.rho ├── fanmailBad.rho ├── fanmailEve.rho ├── fanmailPublish.rho ├── interpolation.rho ├── jackPotNicePrinting.rho ├── jackpot.png ├── jackpot.rho ├── jackpotPublish.rho ├── privateNames.png └── returnEnvelope.png ├── 08-StateChannelsAndMethods ├── README.md ├── README_CN.md ├── box.rho ├── checkMethod.rho ├── clickCounter.png ├── counter.rho ├── counterFactory.rho ├── counterTests.rho ├── patience.rho ├── persistentBox.rho └── variables.png ├── 09-ObjectCapabilities ├── README.md ├── README_CN.md ├── abortableLaunch.rho ├── atc.rho └── savingsStarter.rho ├── 10-MoreSyntax ├── README.md ├── README_CN.md ├── greeter.rho ├── math.rho └── signTest.rho ├── 11-PatternMatching ├── README.md ├── README_CN.md ├── greeter2.rho ├── intersection.rho ├── lookingForMessagesPatternMatching.png ├── matching.rho ├── missileAttack.rho ├── missileSafe.rho ├── missileUnsafe.rho ├── sendASend.rho ├── sugar.png └── union.rho ├── 12-DataStructures ├── README.md ├── capitalOf.rho ├── list.rho ├── map.rho ├── set.rho ├── tuple.rho └── wordLength.rho ├── 13-Iteration └── README.md ├── 14-PlayingGames ├── README.md └── Screenshot-RPS.png ├── 15-GoingOffChain ├── README.md ├── insertArbitrary.rho └── lookup.rho ├── README.md ├── README_CN.md ├── README_RU.md ├── cheatSheet ├── README.md ├── RholangCheetSheet_10.04.18.jpg ├── RholangCheetSheet_10.04.18.pdf └── RholangCheetSheet_10.04.18.png ├── converter ├── README.md ├── index.js ├── package-lock.json └── package.json └── none.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | RawDrawings 2 | outline.txt 3 | timeTracking.txt 4 | converter/node_modules 5 | LongerExamples 6 | 7 | -------------------------------------------------------------------------------- /00-DeveloperEnvironment/README.md: -------------------------------------------------------------------------------- 1 | # Setting up Your Developer Environment 2 | 3 | In order to run the rholang snippets in this tutorial, you will need some kind of development environment. This is not an exhaustive guide to rholang development tools or stacks. Rather, it shows a few common basic development environments to get you started. 4 | 5 | ## RChain Cloud 6 | Members of the RChain community provide a public web-based [online rholang interpreter](http://rchain.cloud) ([mirror](https://rchaincloud.inblock.io)). This tool is the easiest way to get started and does not require installing any software. 7 | 8 | ## Cryptofex IDE 9 | Pyrofex is developing an up-and-coming integrated development environment called [cryptofex](https://cryptofex.io/). Cryptofex runs natively on windows, mac, and linux/. It offers rholang syntax highlighting and is capable of evaluating rholang code internally or with a running RNode. The IDE also supports ethereum development. 10 | 11 | WARNING: As of October 2018, Cryptofex does not report the correct line numbers when you make syntax errors. This can be quite frustrating. 12 | 13 | ## Local Node 14 | The tried and true way to run rholang code is to start up your own local RNode and use its rholang interpreter. First, you'll have to [install RNode](https://rchain.atlassian.net/wiki/spaces/CORE/pages/428376065/User+guide+for+running+RNode) for your platform. 15 | 16 | For novice learners there are step-by-step guides on setting up a node using [AWS](https://blog.rchain.coop/running-rnode-0-5-3-on-amazon-ec2/) or [Docker](https://blog.rchain.coop/running-rnodev-0-6-x-with-docker/). 17 | 18 | Once RNode is installed, you can run a basic standalone node 19 | ``` 20 | $ rnode run -s -n 21 | ``` 22 | 23 | In a separate terminal, you can use RNode's eval mode to evaluate code. 24 | 25 | ``` 26 | $ rnode eval intersection.rho 27 | Evaluating from intersection.rho 28 | 29 | Result for intersection.rho: 30 | Deployment cost: CostAccount(39,Cost(1132)) 31 | Storage Contents: 32 | @{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 } 33 | ``` 34 | 35 | Some of RNode's output is shown in the same terminal that you run the code in. But other output comes directly from the node (the first terminal). So be sure to check both places until you're familiar with what output is displayed where. 36 | -------------------------------------------------------------------------------- /00-DeveloperEnvironment/README_CN.md: -------------------------------------------------------------------------------- 1 | # 配置你的开发环境 2 | 3 | 为了可以运行这个教程里面的rholang代码,你需要一些开发环境。 4 | 这不是一个会让你感到疲惫的rholang开发工具或者技术栈。 5 | 然而它展示了一些基本的开发环境给你开始。 6 | 7 | ## 网上编译器 8 | RChain社区的成员提供了一个基于公共网站的[在线rholang编译器](http://rchain.cloud)。 9 | 这个工具非常有前途,也是一种入门的简单方式。 10 | 但是它还是开发节点,有时候会不稳定。 11 | 12 | ## 本地节点 13 | 真正正确运行rholang代码的方法是在通过启动你自己本地机子的RNode然后使用它的rholang编译器。 14 | 首先你要为你自己的平台[安装 RNode](https://rchain.atlassian.net/wiki/spaces/CORE/pages/428376065/User+guide+for+running+RNode) 15 | 16 | 对于初学者,这里有详细的一步一步指导你怎么使用[AWS](https://blog.rchain.coop/running-rnode-0-5-3-on-amazon-ec2/) 或者[Docker](https://blog.rchain.coop/running-rnodev-0-6-x-with-docker/)启动你的节点. 17 | 18 | 一旦你的RNode安装好了,你可以运行基本的独立节点。 19 | ``` 20 | $ rnode run -s -n 21 | ``` 22 | 23 | 在单独的终端里,你可以在REPL模式下一次执行一行rholang。 24 | ``` 25 | $ rnode repl 26 | 27 | ╦═╗┌─┐┬ ┬┌─┐┬┌┐┌ ╔╗╔┌─┐┌┬┐┌─┐ ╦═╗╔═╗╔═╗╦ 28 | ╠╦╝│ ├─┤├─┤││││ ║║║│ │ ││├┤ ╠╦╝║╣ ╠═╝║ 29 | ╩╚═└─┘┴ ┴┴ ┴┴┘└┘ ╝╚╝└─┘─┴┘└─┘ ╩╚═╚═╝╩ ╩═╝ 30 | 31 | rholang $ Nil 32 | 33 | Deployment cost: CostAccount(0,Cost(0)) 34 | Storage Contents: 35 | 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 } 36 | 37 | rholang $ @"world"!("hello") 38 | 39 | Deployment cost: CostAccount(5,Cost(64)) 40 | Storage Contents: 41 | @{"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 } 42 | ``` 43 | 44 | 当你运行更多行数的rholang代码时候,你可以使用RNode的eval模式来执行代码。 45 | 46 | ``` 47 | $ rnode eval intersection.rho 48 | Evaluating from intersection.rho 49 | 50 | Result for intersection.rho: 51 | Deployment cost: CostAccount(39,Cost(1132)) 52 | Storage Contents: 53 | @{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 } 54 | ``` 55 | 56 | 有一些RNode的输出会出现在你运行代码的同一个终端。但是其它一些代码输出会直接出现在第一个终端。 57 | 所以在你熟悉什么输出出现在哪里前请确定好检查两边的终端。 58 | 59 | ## Cryptofex IDE 60 | 一个叫做[cryptofex](https://cryptofex.io/) 的开发环境已经进入了alpha版本。 61 | Cryptofex可能最后最好的开发rholang的地方,但是现在还是很早期的软件。 62 | Cryptofex提供rholang语法高亮特性并且可以在RChain集成节点上检测dApps。 63 | IDE同时也提供环境创建和测试在以太网上,私人测试网上和单独模式的EVM上的智能合约。 -------------------------------------------------------------------------------- /00-DeveloperEnvironment/README_RU.md: -------------------------------------------------------------------------------- 1 | # Подготовка среды разработки 2 | 3 | Нам понадобится среда разработки, чтобы запускать примеры из туториала. Перечисленные способы -- далеко не полное описание всех инструментов для разработки на ро. Ниже мы предлагаем несколько инстументов, с которых можно начать изучение языка. 4 | 5 | ## Онлайн интерпретатор 6 | Сообщество RChain поддерживает публичный веб-сервер, на котором размещен [онлайн интерпретатор ро](http://rchain.cloud). Это очень доступный инструмент, использование которого не требует никакой предварительной подготовки. 7 | 8 | ## Локальная нода 9 | Самый правительный и проверенный путь исполнять код, написанный на ро, -- установить собственную ноду `rnode` и использовать интерпретатор на ней. Для этого нужно следовать инструкции [по установке](https://rchain.atlassian.net/wiki/spaces/CORE/pages/428376065/User+guide+for+running+RNode) для вашей платформе. 10 | 11 | Самый простой способ для новичков - это установить ноду на облаке [AWS](https://blog.rchain.coop/running-rnode-0-5-3-on-amazon-ec2/) или у другого поставщика вычислительных услуг при помощи [Docker](https://blog.rchain.coop/running-rnodev-0-6-x-with-docker/). 12 | 13 | После установки вы можете запустить отдельностоящую ноду следующей командой: 14 | ``` 15 | $ rnode run -s -n 16 | ``` 17 | 18 | В другом терминале мы можем запускать по строчке кода за раз в режиме REPL (read execute print loop). 19 | ``` 20 | $ rnode repl 21 | 22 | ╦═╗┌─┐┬ ┬┌─┐┬┌┐┌ ╔╗╔┌─┐┌┬┐┌─┐ ╦═╗╔═╗╔═╗╦ 23 | ╠╦╝│ ├─┤├─┤││││ ║║║│ │ ││├┤ ╠╦╝║╣ ╠═╝║ 24 | ╩╚═└─┘┴ ┴┴ ┴┴┘└┘ ╝╚╝└─┘─┴┘└─┘ ╩╚═╚═╝╩ ╩═╝ 25 | 26 | rholang $ Nil 27 | 28 | Deployment cost: CostAccount(0,Cost(0)) 29 | Storage Contents: 30 | 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 } 31 | 32 | rholang $ @"world"!("hello") 33 | 34 | Deployment cost: CostAccount(5,Cost(64)) 35 | Storage Contents: 36 | @{"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 } 37 | ``` 38 | 39 | Когда вы захотите запускать более длинные сегменты кода (а это случится очень скоро), то можно выполнять код в несколько строчек в режиме eval. Не забудьте указать путь к файлу с кодом с расширением `.rho`. 40 | 41 | ``` 42 | $ rnode eval intersection.rho 43 | Evaluating from intersection.rho 44 | 45 | Result for intersection.rho: 46 | Deployment cost: CostAccount(39,Cost(1132)) 47 | Storage Contents: 48 | @{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 } 49 | ``` 50 | 51 | Часть ответа ноды появляется в том же терминале, где вы запускали код. Другая часть там, где вы запускали ноду, т.е. в первом терминале. Обязательно проверяйте оба окна, пока не освоитесь, где появляется какая часть. 52 | 53 | ## Cryptofex IDE 54 | Pyrofex готовится выпустить среду разработки приложений на платформах RChain и Etherium под названием [cryptofex](https://cryptofex.io/). Сейчас она находится в alpha стадии. При помощи этого IDE можно создавать не только dApp для RChain, но и смартконтракты для EVM. 55 | 56 | ## Плагин для IntelliJ IDEA 57 | [Он](https://plugins.jetbrains.com/plugin/9833-rholang) подходит и для других редакторов и сред разработки, включая PhpStorm, AppCode, GoLand, Android Studio и др. Предлагает подсветку систаксиса и другие полезные при написании программ фичи. 58 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/README.md: -------------------------------------------------------------------------------- 1 | # Sending and Standard Out 2 | 3 | ## Say Hello 4 | 5 | !["Person waiving hello"](helloWorld.png) 6 | 7 | 8 | There is a long-standing tradition in programming that your first program should say "Hello World". Here's the simplest rholang code to put that text on the screen. 9 | 10 | [hello.rho](hello.rho) 11 | 12 | ### Exercise 13 | Make the program print "Rholang rocks!" instead of "Hello World". 14 | 15 | 16 | ## WTH is stdout? 17 | 18 | ![Channels are like mailboxes for sending messages](mailbox.png) 19 | 20 | The heart of rholang is communicating on channels. Channels are communication lines that you use to send and receive messages. To send a message on a channel, you use the `!` character. 21 | 22 | ![Redo this diagram!](sendSyntax.png) 23 | 24 | We created the channel `stdout` on the first line of the program with `new stdout`. You'll create lots of channels as you learn rholang. We also gave our channel a special power by including `(rho:io:stdout)`. More on that later, but for now just know that you need that part in parentheses to make text actually appear on the screen. 25 | 26 | 27 | ## Using other channels 28 | 29 | ![Sent messages wait to be received here in "message purgatory"... JK, it's called the "tuplespace"](mailboxes.png) 30 | 31 | You can actually send messages on lots of channels, not just `stdout`. But unlike `stdout` they won't display on the screen because we won't add any special powers to them. 32 | 33 | [tupleSpace.rho](tupleSpace.rho) 34 | 35 | So where do the other channels go then? Nowhere! Not yet anyway. The messages just sit there waiting for someone (or some process) to receive them. We'll learn how to receive messages in the next lesson. The place where messages sit in the meantime is called the "tuplespace". 36 | 37 | Make sure your message is sitting in the tuplespace. You should see some text like this depending on which developer environment you use. 38 | 39 | ``` 40 | Storage Contents: 41 | @{"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 } 42 | ``` 43 | 44 | 45 | 46 | ## Doing two things at once 47 | ![Rather than following an ordered list, all ingredients are added concurrently. Looks delicions](cooking.png) 48 | 49 | In rholang we don't tell the computer to do one thing, then another, then a third. Rather we tell it all the things to do, and it does them "concurrently," or all at once. 50 | 51 | [parallel.rho](parallel.rho) 52 | 53 | The `|` is pronounced "parallel", or "par" for short. 54 | 55 | 56 | ### Exercise 57 | Send the message "1 large pepperoni please" on a channel called "pizza shop". 58 | 59 | ### Exercise 60 | Send "Hi Mom" on the channel "Mom's Phone". 61 | 62 | ### Exercise 63 | Print two messages, "Rick" and "Morty", on the screen in one program. 64 | 65 | 66 | 67 | ## Quiz 68 | 69 | What will `stdout!("Programming!")` print to the screen? 70 | - [x] Programming! 71 | - [ ] stdout! 72 | - [ ] Nothing 73 | 74 | 75 | What channel does `what!("Up")` send a message on? 76 | - [ ] `Up` 77 | - [x] `what` 78 | - [ ] `what` 79 | - [ ] `stdout` 80 | 81 | 82 | Which does rholang do first in 83 | ``` 84 | stdout!("Dogs") 85 | | 86 | stdout!("Cats") 87 | ``` 88 | - [ ] prints "Dogs" 89 | - [ ] prints "Cats" 90 | - [x] Neither. They are concurrent 91 | 92 | 93 | ### Exercise 94 | There is also a special channel called `rho:io:stderr`. Check out what happens when you send to it. ([what's the difference?](https://en.wikipedia.org/wiki/Standard_streams)) 95 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/README_CN.md: -------------------------------------------------------------------------------- 1 | # 发送与标准输出(stdout) 2 | 3 | ## 说声Hello 4 | 5 | !["Person waiving hello"](helloWorld.png) 6 | 7 | 8 | 编程界有一个存在已久的传统——输出"Hello World"应该是你学习的第一个程序。下面是一个在屏幕上输出"Hello World"的最简单例子。 9 | 10 | [hello.rho](hello.rho) 11 | 12 | 13 | 14 | ### 练习 15 | 请让程序输出"Rholang rocks!" 而不是 "Hello World"。 16 | 17 | ### 练习 18 | 尝试将"stdout"替换为别的语句。会得到什么结果? 19 | * 尝试一下这个有趣的通道名称`@"someChannel"`. 20 | * 这里可以比较随意。请让程序在屏幕上输出 "Sup World"。 21 | 22 | 23 | ## 标准输出(stdout)到底是什么东西 24 | 25 | ![Channels are like mailboxes for sending messages](mailbox.png) 26 | 27 | rho语言的核心是通道(channel,下面都称为通道)通信. 通道是你可以用来发送和接收消息的通信线路。你可以使用`!`字符来在通道中发送消息。 28 | 29 | ![Redo this diagram!](sendSyntax.png) 30 | 31 | `stdout` 是一个特殊的通道,用于将文本发送至"标准输出",通常指你的电脑屏幕。正因为它的特殊,我们不得不将它写在第一段学习的代码里面。 32 | 33 | 34 | ## 使用其他通道 35 | 36 | ![Sent messages wait to be received here in "message purgatory"... JK, it's called the "tuplespace"](mailboxes.png) 37 | 38 | 实际上你可以在很多通道中发送消息,而非只有`stdout`。 但其它通道不像 `stdout` 他们不会在屏幕上显示。 39 | 40 | [tupleSpace.rho](tupleSpace.rho) 41 | 42 | 那么,在其他通道中的消息将被发送至哪里?哪里都不会去!这些消息暂时哪儿都不去,这些消息会继续待在通道内,等待其他人去取出它们。我们将在下一课程中学习如何获取这些消息。同时,消息滞留所在的地方,我们称为 "元组空间"。 43 | 44 | 请确保你的信息保留在元组空间里。你应该会看到像下面的信息。 45 | 46 | ``` 47 | Storage Contents: 48 | @{"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 } 49 | ``` 50 | 51 | 52 | 53 | ## 同时做两件事 54 | ![Rather than following an ordered list, all ingredients are added concurrently. Looks delicions](cooking.png) 55 | 56 | 在rholang中,我们不会告诉计算机做完一件事,再到另一件。相反,我们会告诉它需要做的所有事情,然后"并行地"执行它们,或者一次性全部执行。 57 | 58 | [parallel.rho](parallel.rho) 59 | 60 | | 的发音是 "parallel", 可简称为 "par"。 61 | 62 | 63 | ### 练习 64 | 向"pizza shop"通道发送消息"1 large pepperoni please"。 65 | 66 | ### 练习 67 | 向"Mom's Phone"通道发送"Hi Mom"。 68 | 69 | ### 练习 70 | 用一个程序在屏幕上输出两个消息,"Rick"和 "Morty"。 71 | 72 | 73 | ## 小测试 74 | 75 | `stdout!("Programming!")` 将在屏幕上输出什么? 76 | - [x] Programming! 77 | - [ ] stdout! 78 | - [ ] Nothing 79 | 80 | 81 | `@"what"!("Up")` 在什么通道上发送消息? 82 | - [ ] `@"Up"` 83 | - [x] `@"what"` 84 | - [ ] `what` 85 | 86 | 87 | rholang会先执行哪一条语句? 88 | ``` 89 | @"stdout"!("Dogs") 90 | | 91 | @"stdout"!("Cats") 92 | ``` 93 | - [ ] 输出 "Dogs" 94 | - [ ] 输出 "Cats" 95 | - [x] 都不。 它们是并行的 96 | 97 | 98 | PS. 有一个特殊的通道 stderr. 请尝试一下看看往这个通道发送消息,会发生什么? 99 | 100 | [有什么区别?](https://en.wikipedia.org/wiki/Standard_streams) 101 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/README_RU.md: -------------------------------------------------------------------------------- 1 | # Отправка сообщений и страндартный Out 2 | 3 | ## Скажем Привет 4 | 5 | !["Person waiving hello"](helloWorld.png) 6 | 7 | 8 | По старой традиции научимся вначале здороваться на новом языке программирования. Напишем на экране фразу "Hello World". Вот элементарный код на ро, который отображает некий текст. 9 | 10 | [hello.rho](hello.rho) 11 | 12 | 13 | 14 | ### Упражнение 15 | Напишите программу, которая выводит на экран "Ро рулит!" вместо "Hello World". 16 | 17 | ### Упражнение 18 | Попробуйте заменить "stdout" на что-либо ещё. Какие результаты вы получили? 19 | * попробуйте использовать другое имя канала, например `@"someChannel"`. 20 | * обойдемся без лишних церемоний. Давайте скажем `"Здоров, а-р-р-чейн!"`. 21 | 22 | 23 | ## Что такое stdout? 24 | 25 | ![Channels are like mailboxes for sending messages](mailbox.png) 26 | 27 | Программирование на ро построено вокруг взаимодействия на каналах. Каналы - это линии коммуникации, по которым можно отправлять и получать сообщения. Для отправки сообщения по каналу используется символ `!`. 28 | 29 | 30 | ![Redo this diagram!](sendSyntax.png) 31 | `friend` -- имя канала 32 | `!` -- символ отправки 33 | `"Hey There"` -- тело сообщения в круглых скобках 34 | 35 | `stdout` -- специальный канал, который передаёт данные на стандартный поток вывода. В большинстве случаев это выводит их на экран. Так как это специальный канал, мы должны отдельно прописать его в первой строке. 36 | 37 | 38 | ## Используем другие каналы 39 | 40 | ![Sent messages wait to be received here in "message purgatory"... JK, it's called the "tuplespace"](mailboxes.png) 41 | 42 | Сообщения можно отправлять на любой канал, не только на `stdout`. Но в отличие от `stdout` такие сообщения не будут отображаться на экране. 43 | 44 | [tupleSpace.rho](tupleSpace.rho) 45 | 46 | Куда же тогда деваются сообщения, отправленные на другие каналы? Никуда! Сообщения просто лежат в хранилище (пространстве кортежей) и ждут, пока кто-то не получит или "поглотит" ("consume") их. Мы научимся поглощать сообщения в следующем уроке. 47 | 48 | Убедимся, что сообщение всё еще находится в пространстве кортежей. (Помните, что если вы пользуетесь онлайн интерпретатором, то пространство кортежей обнуняется при каждом выполнении). Мы должны видеть нечто похожее на следующий код: 49 | 50 | ``` 51 | Storage Contents: 52 | @{"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 } 53 | ``` 54 | 55 | 56 | 57 | ## Делаем два дела сразу 58 | ![Rather than following an ordered list, all ingredients are added concurrently. Looks delicions](cooking.png) 59 | 60 | В ро мы не говорим компьютеру сделать одну операция, затем другую, а после - третью. Мы сообщаем все действия, которые нужно сделать, и он выполняет их одновременно, все сразу. 61 | 62 | [parallel.rho](parallel.rho) 63 | 64 | Знак `|` читается как "параллельно" или просто "пар" для краткости. 65 | 66 | 67 | ### Упражнение 68 | Отправьте сообщение "1 большую с пепперони, пожалуйста" на канал с именем "Бургеры Боба". 69 | 70 | ### Упражнение 71 | Отправьте "Привет, мам" на канал "мамин телефон". 72 | 73 | ### Упражнение 74 | Выведите три сообщения: "Рик", "Морти" и "Снежок" на экран в одной программе. Выполните эту программу несколько раз, посмотрите, в каком порядке выводятся эти сообщения. 75 | 76 | 77 | 78 | ## Тест 79 | 80 | Что выведет на экран фраза `stdout!("Programming!")` ? 81 | - [x] Programming! 82 | - [ ] stdout! 83 | - [ ] Ничего 84 | 85 | 86 | Какой канал посылает сообщение фраза `@"what"!("Up")` ? 87 | - [ ] `@"Up"` 88 | - [x] `@"what"` 89 | - [ ] `what` 90 | 91 | 92 | Что виртуальная машина ро сделает вначале, выполняя следующий код? 93 | ``` 94 | @"stdout"!("Dogs") 95 | | 96 | @"stdout"!("Cats") 97 | ``` 98 | - [ ] напечатает "Dogs" 99 | - [ ] напечатает "Cats" 100 | - [x] Ни то, ни другое. Эти события произойдут одновременно и параллельно. 101 | 102 | 103 | PS. Есть ещё один специальный канал `stderr`. Посмотрите, что будет, если послать сообщение на него. 104 | ``` 105 | new stderr(`rho:io:stderr`) in { 106 | stderr!("Danger! This is your Emperor speaking. There is danger here.") 107 | } 108 | ``` 109 | 110 | [В чем разница между stdout и stderr?](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B8) 111 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/cooking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/01-SendingAndStandardOut/cooking.png -------------------------------------------------------------------------------- /01-SendingAndStandardOut/hello.rho: -------------------------------------------------------------------------------- 1 | new stdout(`rho:io:stdout`) in { 2 | stdout!("Hello World!") 3 | } 4 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/helloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/01-SendingAndStandardOut/helloWorld.png -------------------------------------------------------------------------------- /01-SendingAndStandardOut/mailbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/01-SendingAndStandardOut/mailbox.png -------------------------------------------------------------------------------- /01-SendingAndStandardOut/mailboxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/01-SendingAndStandardOut/mailboxes.png -------------------------------------------------------------------------------- /01-SendingAndStandardOut/parallel.rho: -------------------------------------------------------------------------------- 1 | new chan1, stdout(`rho:io:stdout`) in { 2 | stdout!("I'm on the screen") 3 | | 4 | chan1!("I'm in the tuplespace") 5 | } 6 | -------------------------------------------------------------------------------- /01-SendingAndStandardOut/sendSyntax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/01-SendingAndStandardOut/sendSyntax.png -------------------------------------------------------------------------------- /01-SendingAndStandardOut/tupleSpace.rho: -------------------------------------------------------------------------------- 1 | new randoChannel in { 2 | randoChannel!("This won't be on the screen") 3 | } 4 | -------------------------------------------------------------------------------- /02-Receiving/Keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/02-Receiving/Keys.png -------------------------------------------------------------------------------- /02-Receiving/README.md: -------------------------------------------------------------------------------- 1 | # Receiving 2 | 3 | ## Check for Messages 4 | 5 | ![// Dear future self, keys in freezer because...](Keys.png) 6 | 7 | We learned last time how to send a message. Now it's time to learn how to receive a message. The general syntax is: 8 | 9 | `for(message <- channel){ 10 | // Do something here 11 | }` 12 | 13 | When some message show up on `channel` it gets received and is referred to as `message`. The code inside the curly braces, `{}`, is called a "continuation" and it runs when a message is received. 14 | 15 | BTW, lines that start with `//` are called comments. They're just there for human coders and don't affect the way the program runs at all. They're a good idea, and you should use them! Anyone who reads your code will appreciate them (including your future self). 16 | 17 | 18 | ## Comm Events 19 | 20 | ![Pizza shop can receive messages on its channel.](pizza.png) 21 | 22 | The following code sends a message on a channel for a pizza shop and the pizza shop receives it. The pizza shop acknowledges receiving the message by printing to `stdout`. 23 | 24 | [pizzaOrder](pizzaOrder.rho) 25 | 26 | ### Exercise 27 | Send that message to a different channel like `coffeShop`. Did the acknowledgement print? Is anything left in the tuplespace? 28 | 29 | ![Let's hit up the coffee shop.](coffee.png) 30 | 31 | ### Exercise 32 | Remember, in rholang things don't happen in any particular order, they happen concurrently. The pizza shop code will work just as well if we put the receive first. Give it a try! 33 | 34 | 35 | ## Receiving Before Sending 36 | 37 | ![Rather than the message appearing first, then someone receiving it, Bob is trying to receive first. Hopefully someone will send him a message so he can have a comm event.](lookingForMessages.png) 38 | 39 | When a send and a receive come together on a channel, it is called a communication event, or "comm event" for short. 40 | 41 | Unlike normal mail where a message must be sent _then_ received, the two can happen in either order or at the same time in rholang. It is just as acceptable to receive a message, then send it. Whenever a send and receive come together, a comm event takes place. 42 | 43 | 44 | ## Contracts 45 | 46 | ![The poor chef is too busy making sure he can receive orders to take care of his pizza.](pizzaBurning.png) 47 | 48 | Our pizza shop example illustrates comm events nicely, but it isn't very realistic to expect the pizza shop to manually issue a new receive every time an incoming order consumes theirs from the tuplespace. 49 | 50 | Luckily it's possible to deploy code once, and have it run _every_ time it receives a message. This kind of thing is called a "smart contract". Let's look at some code for a coffee shop that is much superior to the pizza shop. 51 | 52 | [coffeeShop.rho](coffeeShop.rho) 53 | 54 | 55 | ### Exercise 56 | Order more drinks from the coffee shop 57 | 58 | ### Exercise 59 | Change the acknowledgement message that the coffee shop prints when it receives an order. 60 | 61 | Which should generally come first? 62 | - [ ] A send because that's how normal mail works. 63 | - [ ] A receive because it's faster to run the code that way. 64 | - [x] Either a send or a receive can come first, or they can come together. 65 | - [ ] A receive because rholang is concurrent. 66 | - [ ] Neither. Just make a comm event directly. 67 | 68 | ### Exercise 69 | The channel is just named `coffeeShop`. Change it to be named after a specific coffee shop of your choosing. 70 | 71 | 72 | ## Persistent For 73 | There are actually two different styles of syntax in rholang to achieve this persistent behavior. We just learned about `contract`, the other looks much more like a regular receive. The following snippets are equivalent. 74 | 75 | ```rholang 76 | contract coffeeShop(order) = { 77 | ``` 78 | 79 | ```rholang 80 | for(order <= coffeeShop) { 81 | ``` 82 | Notice this is different from a normal `for` because it has a double arrow `<=` rather than a single arrow `<-`. The only difference between the persistent for and a contract comes when we start talking about blockchains. For now you can think of them as the same thing. 83 | 84 | ### Exercise 85 | The pizza shop could use a contract like the one the coffee shop had. Let's write it one but use a persistent for instead of a contract. Try to write the entire thing from scratch so you remember the syntax better. 86 | 88 | 89 | 90 | Which of these things is not like the other? 91 | - [x] `for (a <- b){}` 92 | - [ ] `contract b(a) = {}` 93 | - [ ] `for (a <= b){}` 94 | 95 | Which send will produce a comm event with `for (message <- grandmasSnapChat){Nil}`? 96 | - [ ] `for(grandmasSnapChat)!("Hi Grandma")` 97 | - [x] `grandmasSnapChat!("Glad you're snapping Grandma")` 98 | - [ ] `for("Here's a snap for you g'ma" <- grandmasSnapChat)` 99 | -------------------------------------------------------------------------------- /02-Receiving/README_CN.md: -------------------------------------------------------------------------------- 1 | # 接收 2 | 3 | ## 消息检查 4 | 5 | ![// Dear future self, keys in freezer because...](Keys.png) 6 | 7 | 在上一章我们学习了如何发送消息。现在是时候学习如何接收消息了。常规语法如下: 8 | 9 | `for(message <- channel){ // Do something here}` 10 | 11 | 顺便提一下, // 用于标示注释。 //后面的内容程序并不会运行。写好注释可以有利于其他开发者(包括你自己)阅读代码,并了解代码的意图,其他读你代码的开发者会感激你写注释的。 12 | 13 | 14 | 15 | ## 通信事件 16 | 17 | ![Pizza shop can receive messages on its channel.](pizza.png) 18 | 19 | 下面的代码使用披萨店的通道发送了一个消息,披萨店收到了它。pizza店通过将消息打印至标准输出来表明其已收到。 20 | 21 | [pizzaOrder](pizzaOrder.rho) 22 | 23 | ### 练习 24 | 将上述消息发送至一个不同的通道,如`@"coffeShop"`. 消息会被接收端打印出来吗? 还是东西留在了元组空间里么? 25 | 26 | ![Let's hit up the coffee shop.](coffee.png) 27 | 28 | ### 练习 29 | 记住,在rholang中,任何事情都是并行地而非按顺序地执行。如果我们把接收信息的代码放在前面,那么披萨店的代码仍可执行。尝试一下吧。 30 | 31 | ## 元组空间污染 32 | 33 | 如果你遇到了旧数据滞留在元组空间并会对后面的代码执行有影响,你需要清空你的元组空间。最简单的方式是删除你的数据目录`.rnode` 34 | 35 | 使用上述方法清空元组空间已经过时了。一个更好的方法是防止它一开始被旧数据污染。我们可以通过修改最上面的new代码段来实现。 36 | 37 | 旧的方案 38 | ``` 39 | new stdout(`rho:io:stdout`) in { 40 | @"world"!("Welcome to RChain") 41 | } 42 | ``` 43 | 44 | 尝试下面新的方案 45 | ``` 46 | new world, stdout(`rho:io:stdout`) in { 47 | world!("Welcome to RChain") // No more @ or " " 48 | } 49 | ``` 50 | 我们将在“不可伪造的names”的课程中讲解它的原理。现在你不需要每次都重置通道。 51 | 52 | ## 发送前接收 53 | 54 | ![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.](lookingForMessages.png) 55 | 56 | 当发送和接收同时存在于通道时,这被称为通信事件,或称为"comm event"。 57 | 58 | 不像普通邮件那样必须被发送,对方才能被接收,在rholang中,上述两个事件可以以任何顺序发生或者同时发生。这类似于可以先接收消息,再发送它。每当发送和接收共存时,就会触发通信事件。 59 | 60 | 61 | ## 合约 62 | 63 | ![The poor chef is too busy making sure he can receive orders to take care of his pizza.](pizzaBurning.png) 64 | 65 | 我们的披萨店例子很好地说明了通信事件,但期望每次有新的订单时,披萨店都能自动发出一个新的接收来处理它们,这并不现实。 66 | 67 | 幸运地是,我们可以只部署一次代码,然后每次接收到它的消息时都执行一次。这类代码称为“智能合约”。让我们看一个比披萨店更高级但相似的例子--咖啡店。 68 | 69 | [coffeeShop.rho](coffeeShop.rho) 70 | 71 | 72 | ### 练习 73 | 在咖啡店点第二杯饮料 74 | 75 | ### 练习 76 | 更改上面例子的确认消息 77 | 78 | 一般来说,下列哪一个会第一个发生? 79 | - [ ] 发送,因为它与普通邮件的工作原理一样。 80 | - [ ] 接收,因为以该方式运行的代码更快。 81 | - [x] 发送或接收都可以最先发生,或者同时。 82 | - [ ] 接收,因为rohlang是并行的。 83 | - [ ] 都不。直接触发通信事件(comm event)。 84 | 85 | ### 练习 86 | 通道被命名为 `@"coffeeShop"`。将它更名为你所选择的特定咖啡店的名称。然后使用我们最近学到的`new`来修改代码 87 | 88 | 89 | 90 | ## Persistent For 91 | 实际上,在rholang中有两种不同的语法来表示持续从通道取出信息。我们刚刚学习`contract`语法。下面的用for语法的代码是等价的。 92 | 93 | 94 | ```rholang 95 | contract @"coffeeShop"(order) = { 96 | ``` 97 | 98 | ```rholang 99 | for(order <= @"coffeeShop") { 100 | ``` 101 | 注意,上述代码与正常的 `for` 不同,因为它使用了双划线 `<=` 而不是单划线 `<-`. `for`和`contract`是有不同的地方的,我们会在讨论区块链的时候讨论到他们的区别。现在你可以将它们当做同一功能。 102 | 103 | ### 练习 104 | 用持久的for语法而不是"contract"语法来写一个想咖啡店这样的披萨店合约。尝试自己从头写一次整个代码,这样会让你更容易记清语法。 105 | 107 | 108 | 109 | 下面哪一项是与其他两项不同的? 110 | - [x] `for (a <- b){}` 111 | - [ ] `contract b(a) = {}` 112 | - [ ] `for (a <= b){}` 113 | 114 | 哪一个发送语句会与`for (message <- @"grandmasSnapChat"){Nil}`对应产生一个通信事件 ? 115 | - [ ] `grandmasSnapChat!("Hi Grandma")` 116 | - [x] `@"grandmasSnapChat"!("Glad you're snapping Grandma")` 117 | - [ ] `for("Here's a snap for you g'ma" <- @"grandmasSnapChat")` 118 | -------------------------------------------------------------------------------- /02-Receiving/README_RU.md: -------------------------------------------------------------------------------- 1 | # Получение сообщений 2 | 3 | ## Проверка сообщений 4 | 5 | ![// Dear future self, keys in freezer because...](Keys.png) 6 | 7 | В предыдущем уроке мы научились отправлять сообщения. Сейчас время научиться их получать. Синтаксис для этого в самом общем случае выглядит так: 8 | 9 | `for(message <- channel){ // Тут мы что-то делаем}` 10 | 11 | Кстати, строчки, которые начинаются с `//` называются комментариями. Они полезны только для разработчиков и не влияют на поведение программы. Тщательно прокомментированный код легче читать и понимать. Особенно, когда разбираешь старые программы. 12 | 13 | ## Коммуникационные события 14 | 15 | ![Pizza shop can receive messages on its channel.](pizza.png) 16 | 17 | Следующий код отправляет сообщение на канал пиццерии, а пиццерия его получает. Пиццерия подтверждает получение сообщения через stdout. 18 | 19 | [pizzaOrder](pizzaOrder.rho) 20 | 21 | ### Упражнение 22 | Отправьте сообщение на другой канал, например `@"coffeShop"`. Выводится ли подтверждение? Остается ли что-либо в хранилище? 23 | 24 | ![Let's hit up the coffee shop.](coffee.png) 25 | 26 | ### Упражнение 27 | Помните, в ро всё происходит не по порядку, в котором написано, а одновременно. Код пиццерии будет работать так же хорошо, если мы пропишем поглощение сообщения вначале. Попробуйте поменять местами отправку и получение. 28 | 29 | ## Завалы в хранилище 30 | 31 | Если вы сталкиваетесь с проблемами из-за того, что старые данные остаются в хранилище и вылезают в ненужный момент, то вам надо очистить пространство кортежей. Самый простой способ это сделать -- удалить директорию с данными, которая обычно называется`.rnode` 32 | 33 | 34 | Регулярно подчищать хранилище - утомительное занятие. Было бы лучше, что оно вообще не захламлялось. Мы можем сделать это, изменив самую первую строчку кода со словом `new`. 35 | 36 | Вместо старого подхода 37 | ``` 38 | new stdout(`rho:io:stdout`) in { 39 | @"world"!("Welcome to RChain") 40 | } 41 | ``` 42 | 43 | Попробуем следующее 44 | ``` 45 | new world, stdout(`rho:io:stdout`) in { 46 | world!("Welcome to RChain") // No more @ or " " 47 | } 48 | ``` 49 | Мы обсудим, как это всё работает в уроке по Неподделаемым именам. Пока же нам достаточно того, что кортеж не захламляется. 50 | 51 | ## Получение перед отправкой 52 | 53 | ![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.](lookingForMessages.png) 54 | 55 | Когда на канале возникают отправка и получение, то такой случай называется коммуникационным событием или "комм-событием" для краткости. 56 | 57 | В отличие от обычной почти, где сообщение нужно сначала отправить, а только затем его можно получить, в ро эти два события могут происходить в любой последовательности или одновременно. Когда отправка и получение возникают на канале, то происходит "комм-событие". 58 | 59 | 60 | 61 | ## Контракты 62 | 63 | ![The poor chef is too busy making sure he can receive orders to take care of his pizza.](pizzaBurning.png) 64 | 65 | Наш пример с пиццерией служит хорошей иллюстрацией комм-событий. Однако врядли пиццерия будет вручную создавать новое событие получения для каждого заказа, когда каждый новый заказ будет поглощать его из хранилища. 66 | 67 | К счастью, у нас есть возможность разместить код один раз, а затем выполнять его каждый раз, когда мы получаем сообщение. Такой прием называют "контрактом". Давайте взглянем на код для кофейни, который гораздо лучше, чем код для пиццерии. 68 | 69 | [coffeeShop.rho](coffeeShop.rho) 70 | 71 | 72 | ### Упражнение 73 | Закажите в кофейне третий напиток 74 | 75 | ### Упражнение 76 | Измените сообщение с подтверждением 77 | 78 | ### Тест 79 | Что обычно происходит в первую очередь? 80 | - [ ] Отправка, потому что так обычно происходит с письмами. 81 | - [ ] Получение, так как в таком случае код исполняется быстрее. 82 | - [x] И отправка, и получение могут быть первыми, или же они могут произойти одновременно. 83 | - [ ] Ни то, ни другое. Сразу происходит коммуникационное событие. 84 | 85 | ### Упражнение 86 | Сейчас имя канала просто `@"coffeeShop"`. Измените его на название вашей любимой кофейни. И заодно имените код, используя `new` новым образом, как мы только что научились. Т.е. без `@` и кавычек. 87 | 88 | 89 | 90 | ## Персистентный For 91 | В ро есть два различных систаксических стиля, при помощи которых можно добиться персистентного поведения кода.Только что мы познакомились с `contract`. Это один из стилей. Но есть и другой. Следующие куски кода задают одинаковое поведение. 92 | 93 | ```rholang 94 | contract @"coffeeShop"(order) = { 95 | ``` 96 | 97 | ```rholang 98 | for(order <= @"coffeeShop") { 99 | ``` 100 | Обратите внимание на отличие от обычного выражения с `for`. Здесь используется двойная стрелка`<=` вместо одинарной `<-`. Различия между персистентным `for` и контрактом возникают только в контексте блокчейна. Пока же мы можем считать, что эти два выражения ведут себя одинаково. 101 | 102 | ### Упражнение 103 | Пиццерии тоже нужен контракт, похожий на то, что есть у кофейни. Давайте его напишем, но будем использовать персистентный for вместо контракта. Попробуйте написать его полностью с нуля, чтобы лучше запомнить синтаксис. 104 | 106 | 107 | 108 | Что из этого ведёт себя не так, как два других выражения? 109 | - [x] `for (a <- b){}` 110 | - [ ] `contract b(a) = {}` 111 | - [ ] `for (a <= b){}` 112 | 113 | Что нужно отправить, чтобы создать комм-событие с `for (message <- @"grandmasSnapChat"){Nil}`? 114 | - [ ] `grandmasSnapChat!("Hi Grandma")` 115 | - [x] `@"grandmasSnapChat"!("Glad you're snapping Grandma")` 116 | - [ ] `for("Here's a snap for you g'ma" <- @"grandmasSnapChat")` 117 | -------------------------------------------------------------------------------- /02-Receiving/coffee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/02-Receiving/coffee.png -------------------------------------------------------------------------------- /02-Receiving/coffeeShop.rho: -------------------------------------------------------------------------------- 1 | new coffeeShop, stdout(`rho:io:stdout`) in { 2 | contract coffeeShop(order) = { 3 | stdout!("Coffee Order Received") 4 | } 5 | | 6 | coffeeShop!("one hot chocolate") 7 | | 8 | coffeeShop!("two large cappuccinos please") 9 | } 10 | -------------------------------------------------------------------------------- /02-Receiving/lookingForMessages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/02-Receiving/lookingForMessages.png -------------------------------------------------------------------------------- /02-Receiving/persistentPizzaShop.rho: -------------------------------------------------------------------------------- 1 | new pizzaShop, stdout(`rho:io:stdout`) in { 2 | for (order <= pizzaShop) { 3 | stdout!("Pizza Order Received") 4 | } 5 | | 6 | pizzaShop!("one hot chocolate") 7 | | 8 | pizzaShop!("two large latte's please") 9 | } 10 | -------------------------------------------------------------------------------- /02-Receiving/pizza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/02-Receiving/pizza.png -------------------------------------------------------------------------------- /02-Receiving/pizzaBurning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/02-Receiving/pizzaBurning.png -------------------------------------------------------------------------------- /02-Receiving/pizzaOrder.rho: -------------------------------------------------------------------------------- 1 | new pizzaShop, stdout(`rho:io:stdout`) in { 2 | pizzaShop!("2 medium pies") 3 | | 4 | for(order <- pizzaShop){ 5 | stdout!("Order Received.") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/README.md: -------------------------------------------------------------------------------- 1 | # Telephone, Names, and Processes 2 | 3 | ## Message Relaying 4 | 5 | 6 | ![The game of telephone is perfect to simulate message forwarding in rholang.](telephone.png) 7 | 8 | 9 | We've previously learned how to send a message to grandma or a pizza shop. But so far all those recipients have done is acknowledge the message by printing to standard output. 10 | 11 | Now let's make them do something more interesting by passing the message along like in a child's telephone game 12 | 13 | [telephone3.rho](telephone3.rho) 14 | 15 | As the message says, you learn most when you experiment. So be sure to change things as you see fit. 16 | 17 | ### Exercise 18 | 19 | That telephone game was fun, but it's always better the have more players. Go ahead and add a third player called Charlie. Instead of printing to `stdout`, bob will send the message along to Charlie. Then Charlie will print it to the screen. The More the Merrier! 20 | 21 | 22 | 23 | ![The message never seems to get there correctly. I blame Bob.](telephoneChangedMessage.png) 24 | 25 | 26 | 27 | ### Exercise 28 | If you've ever actually played telephone, you know that the message rarely arrives in tact. Change the program so Bob passes along a different message regardless of what he receives. 29 | 30 | 31 | ## WTH is That `*`? 32 | 33 | ![Opposites attract](inverse.png) 34 | 35 | Did you notice the `*` in `bob!(*message)`? In rholang there are two kinds of things, "channels" and "processes". There are also ways to convert between the two. 36 | 37 | 38 | 39 | A "process" is any piece of rholang code such as our telephone game, or our pizza shop order program. Processes can be big hundred-line programs or small on-liners. They can even be tiny pieces of code that are just values. Here are some example processes. 40 | 41 | - `stdout!("Sup Rholang?")` A common send 42 | - `Nil` The smallest possible process. It literally means "do nothing". 43 | - `for(msg <- phone){Nil}` A common receive that does nothing when a message arrives. 44 | - `"Hello World"` Another small process that also does nothing. These are called "Ground Terms". 45 | 46 | 47 | A channel (also frequently called a "name") is something that can be to send messages over. In rholang, names come from "quoting processes" by putting the `@` sign before a process. Here are some example names. 48 | 49 | - `@"Hello World"` Made by quoting the ground term "Hello World". 50 | - `@Nil` The smallest possible name. Made by quoting the smallest possible process. 51 | - `@(alice!("I like rholang, pass it on."))` Made by quoting a process from our telephone game 52 | 53 | 54 | 55 | ## So What is `*` all about? 56 | 57 | 58 | ![What kind of name is that!? Did your parents just name you after some computer code?](myNameIs.png) 59 | 60 | We can package processes up to make names by quoting them with the `@` symbol. We can also turn names back into processes by "unquoting" them with the `*` symbol. 61 | 62 | The big thing to remember is in rholang we **send processes and receive names**. That's important so I'll say it again. You always **send a process** and on the other end, you **receive a name**. 63 | 64 | When Alice receives our message with `for(message <- alice)` she is receiving, so `message` becomes a name. When she later sends to Bob she has to send a process, so she uses `*` to turn `message` back into a process with `bob!(*message)` 65 | 66 | 67 | 68 | ## Quiz 69 | 70 | What do we send? 71 | - [x] processes 72 | - [ ] names 73 | 74 | 75 | 76 | What do we receive? 77 | - [ ] processes 78 | - [x] names 79 | 80 | 81 | 82 | What is `registration` from the code `new registration in {...}` 83 | - [ ] process 84 | - [x] name 85 | - [ ] invalid syntax 86 | 87 | 88 | 89 | 90 | What is `Nil`? 91 | - [x] process 92 | - [ ] name 93 | - [ ] invalid syntax 94 | 95 | 96 | 97 | What is `@Nil`? 98 | - [ ] process 99 | - [x] name 100 | - [ ] invalid syntax 101 | 102 | 103 | 104 | 105 | What is `@@Nil`? 106 | - [ ] process 107 | - [ ] name 108 | - [x] invalid syntax 109 | 110 | 111 | 112 | `*importantData` is a process, so what is `importantData`? 113 | - [ ] process 114 | - [x] name 115 | - [ ] invalid syntax 116 | 117 | 118 | 119 | Which of these is equivalent to `"BobsPhone"`? 120 | - [x] `*@"BobsPhone"` 121 | - [ ] `@"BobsPhone"` 122 | - [ ] `*"BobsPhone"` 123 | - [ ] `@*"BobsPhone"` 124 | - [ ] `stdout!("BobsPhone")` 125 | 126 | 127 | 128 | ### Exercise 129 | 130 | ![This telephone game has a fork](telephoneFork.png) 131 | 132 | Instead of a linear telephone game where each player passes the message to the next, let's add a branch in the game. So now Bob will send to Charlie like before, but Bob will also send to Dawn. 133 | 134 | Each branch can be as long as you want, but at the end of each branch, print the message to `stdout`. 135 | -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/README_CN.md: -------------------------------------------------------------------------------- 1 | # 传音筒、"name"和“process” 2 | 3 | ## 消息传递 4 | 5 | 6 | ![The game of telephone is perfect to simulate message forwarding in rholang.](telephone.png) 7 | 8 | 9 | 10 | 在前面的章节,我们学习了如何向祖母或披萨店发送消息。但是至今所有的接收方都通过将消息打印至标准输出,来告知已经接收到了。 11 | 12 | 现在让我们做一些更有意思的事情--类似孩子们的传话游戏那样传递消息。 13 | 14 | [telephone3.rho](telephone3.rho) 15 | 16 | 你可以通过运行上面的代码来做实验。你可以修改你觉得合适的地方多运行几次。 17 | 18 | ### 练习 19 | 20 | 传话游戏很有趣,但有更多玩家参与会更好。请添加第三位明教Charlie的玩家。bob接收消息后将发送消息给Charlie,而不是简单打印至`stdout`。然后Charlie将它打印至屏幕上。多多益善! 21 | 22 | 23 | 24 | ![The message never seems to get there correctly. I blame Bob.](telephoneChangedMessage.png) 25 | 26 | 27 | 28 | ### 练习 29 | 如果你曾经玩过电话游戏,你应该知道,消息极少能被正确地传递。Bob现在决定通过发送一条错误的消息。改写程序,使得Bob无论收到什么,都能传递不同的消息。 30 | 31 | 32 | ## *这到底是啥? 33 | 34 | ![Opposites attract](inverse.png) 35 | 36 | 你注意到 `@"Bob"!(*message)`中的`*`? 在rholang中有两种类型, "names" 和 "processes"。同样也有可以在两者之间互相转化的方法。 37 | 38 | 39 | 40 | "processes"可以是rholang中任何一个代码片段,例如我们的传话筒游戏,或者是披萨店订单程序。“process”可以是上百行的大程序,也可以只有几行。它们甚至可以是用于表示值的代码。下面是一些“process”的例子。 41 | 42 | - `stdout!("Sup Rholang?")` 一个常见的发送操作。 43 | - `Nil` 最小的“process”。如字面意思,它不做任何事。 44 | - `for(msg <- @"phone"){Nil}` 一个常见的接收操作,在消息到达时它不会做任何事。 45 | - `"Hello World"` 另一个不做任何事请的小“process”。被称为"基础术语"。 46 | 47 | 48 | "names"可以被用于赋名通道以发送消息。在大多数编程语言中,"name"是完全独立的一样东西,它们本身就存在。但是在rholang中,"name"来自"引用process",即将@标签放在“process”之前,即可得到一个"name"。下面是"name"的一些例子。 49 | 50 | - `@"Hello World"` 通过引用基础术语"Hello World"来创建。 51 | - `@Nil` 最小的“name”。通过引用最小的“process”来创建。 52 | - `@(@"Alice"!("I like rholang, pass it on."))` 通过引用来自传话筒游戏的"process"来创建。 53 | 54 | 55 | 56 | 57 | ## 关于*的一切 58 | 59 | 60 | ![What kind of name is that!? Did your parents just name you after some computer code?](myNameIs.png) 61 | 62 | 通过用`@`符号来标记“process”,我们可以将“process”打包以创建一些“name”。我们也可以通过使用`*`标记“name”,从而将“name”转变为“process”。 63 | 64 | 在rholang中,我们需要记住的是发送“process”和接收“name”。这很重要,因此我再次强调。你总是发送一个“process”,在另一端接收一个“name”。 65 | 66 | Aice通过`for(message <- @"Alice")`接收我们的消息,所以, `message` 变成了一个“name”。当她之后发送给Bob时,她不得不发送“process”,所以她要用`@"Bob"!(*message)`使用`*`将`message`转变回一个“process”。 67 | 68 | 69 | 70 | ## 小测验 71 | 72 | 我们发送什么? 73 | - [x] processes 74 | - [ ] names 75 | 76 | 77 | 78 | 我们接收什么? 79 | - [ ] processes 80 | - [x] names 81 | 82 | 83 | 84 | `@"registration"`是什么? 85 | - [ ] process 86 | - [x] name 87 | - [ ] 非法语法 88 | 89 | 90 | 91 | 92 | `Nil`是什么? 93 | - [x] process 94 | - [ ] name 95 | - [ ] 非法语法 96 | 97 | 98 | 99 | `@Nil`是什么? 100 | - [ ] process 101 | - [x] name 102 | - [ ] 非法语法 103 | 104 | 105 | 106 | 107 | `@@Nil`是什么? 108 | - [ ] process 109 | - [ ] name 110 | - [x] 非法语法 111 | 112 | 113 | 114 | `*importantData` 是一个“process”, 那么`importantData`是什么? 115 | - [ ] process 116 | - [x] name 117 | - [ ] 非法语法 118 | 119 | 120 | 121 | 下面哪一个与`"BobsPhone"`等价? 122 | - [x] `*@"BobsPhone"` 123 | - [ ] `@"BobsPhone"` 124 | - [ ] `*"BobsPhone"` 125 | - [ ] `@*BobsPhone` 126 | - [ ] `stdout!("BobsPhone")` 127 | 128 | 129 | 130 | ### 练习 131 | 132 | ![This telephone game has a fork](telephoneFork.png) 133 | 134 | 不像之前的线性传话游戏那样,每个玩家将信息传递给下一位,我么来为游戏添加一个分支。现在,Bob与先前一样将发送消息给Charlie,但同时也会发送给Elise。 135 | 136 | 每个分支的长度由你定,但在每个分支的最后都得将消息打印至标准输出。 137 | -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/README_RU.md: -------------------------------------------------------------------------------- 1 | # Сломанный телефон, Имена и Процессы 2 | 3 | ## Передаём сообщения дальше 4 | 5 | 6 | ![The game of telephone is perfect to simulate message forwarding in rholang.](telephone.png) 7 | 8 | 9 | 10 | В предыдущем уроке мы научились отправлять сообщение бабушке или пиццерии. Но пока что получатели только подтверждали получение, выводя сообщение на стандартный вывод. 11 | 12 | Давайте теперь попробуем передавать сообщения дальше, как в игре "Сломанный телефон". 13 | 14 | [telephone3.rho](telephone3.rho) 15 | 16 | Как мы уже не раз говорили, эксперимент - лучшая форма обучения. Попробуйте поменять части программы на ваш вкус. 17 | 18 | ### Упражнение 19 | 20 | Первый рауд "сломанного телефона" удался, то будет интересней, если у нас будет больше игроков. Давайте добавим третьего игрока -- Чарли. Боб вместо того, чтобы вывести сообщение на `stdout`, передаст его новому игроку. А затем Чарли напечатает его. Чем больше народу, тем веселей! 21 | 22 | 23 | 24 | ![The message never seems to get there correctly. I blame Bob.](telephoneChangedMessage.png) 25 | 26 | 27 | 28 | ### Упражнение 29 | Если вы когда-нибудь играли в сломанный телефон, то вы в курсе, что сообщения редко когда доходят в целости. Боб решил передать неправильное сообщение. Измените программу, чтобы она передавала от Боба другое сообщение, не зависящее от полученного. 30 | 31 | 32 | ## Что такое эта `*`? 33 | 34 | ![Opposites attract](inverse.png) 35 | 36 | Вы заметили `*` в `@"Bob"!(*message)`? В ро есть два типа объектов "имена" и "процессы". И есть способы превращать одно в другое и обратно. 37 | 38 | 39 | 40 | "Процесс" -- любой кусок кода на ро. Например, наша игра в сломанный телефон или пиццерия из предыдущих уроков. Процессы могуть быть программами на сотни строк или кусочками на одну строчку. Они даже могут быть крошечными фрагментами кода, которые представляют собой значения. Вот примеры процессов: 41 | 42 | - `stdout!("Sup Rholang?")` Обычная отправка 43 | - `Nil` Наименьший возможный процесс. Он буквально значит "ничего не делать". 44 | - `for(msg <- @"phone"){Nil}` Обычное получение, которые ничего не делает, когда поступает сообщение. 45 | - `"Hello World"` Ещё один маленький процесс, который ничего не делает. Такие процессы называются "базовыми выражениями" ("Ground Terms"). 46 | 47 | 48 | "Имя" -- нечто, что можно использовать как канал для передачи сообщений. В большинстве языков программирования, имена -- отдельные сущности, существующие сами по себе. В ро имена получаются в результате "цитирования процессов"("quoting processes") при помощи добавления перед процессом знака`@`. Вот некоторые примеры имен: 49 | 50 | - `@"Hello World"` Получено после цитирования базового выражения "Hello World". 51 | - `@Nil` Наименьшее возможное имя. Получено после цитирования наименьшего возможного процесса. 52 | - `@(@"Alice"!("I like rholang, pass it on."))` Получено после цитирования процесса из нашей игры про телефон. 53 | 54 | 55 | 56 | ## И зачем нам нужна эта `*`? 57 | 58 | 59 | ![What kind of name is that!? Did your parents just name you after some computer code?](myNameIs.png) 60 | 61 | Мы можем запаковать процесс и превратить его в имя, процитировав его при помощи знака `@`. Мы также можем проделать обратную операцию и превращать имена в процессы при помощи символа `*`. 62 | 63 | Самое важное, что нужно запомнить: в ро мы отправляем процессы и получаем имена. Это настолько важно, что стоит повторить. Мы всегда отправляем процесс и, с другой стороны, всегда получаем имя. 64 | 65 | Когда Алиса получает наше сообщение при помощи `for(message <- @"Alice")`, то она -- на принимающей стороне. Т.е.`message` становится именем. Когда она позже отправляет его Бобу, то она должна отправить процесс. И она использует `*`, чтобы превратить `message` обратно в процесс при помощи `@"Bob"!(*message)`. 66 | 67 | 68 | 69 | ## Тест 70 | 71 | Что мы отправляем? 72 | - [x] процессы 73 | - [ ] имена 74 | 75 | 76 | 77 | Что мы получаем? 78 | - [ ] процессы 79 | - [x] имена 80 | 81 | 82 | Что такое `@"registration"`? 83 | - [ ] процесс 84 | - [x] имя 85 | - [ ] синтаксическая ошибка 86 | 87 | 88 | 89 | 90 | What is `Nil`? 91 | - [x] процесс 92 | - [ ] имя 93 | - [ ] синтаксическая ошибка 94 | 95 | 96 | 97 | What is `@Nil`? 98 | - [ ] процесс 99 | - [x] имя 100 | - [ ] синтаксическая ошибка 101 | 102 | 103 | 104 | 105 | Что такое `@@Nil`? 106 | - [ ] процесс 107 | - [ ] имя 108 | - [x] синтаксическая ошибка 109 | 110 | 111 | Если`*importantData` -- это процесс, то что тогда `importantData`? 112 | - [ ] процесс 113 | - [x] имя 114 | - [ ] синтаксическая ошибка 115 | 116 | 117 | 118 | Что из следующего эквивалентно `"BobsPhone"`? 119 | - [x] `*@"BobsPhone"` 120 | - [ ] `@"BobsPhone"` 121 | - [ ] `*"BobsPhone"` 122 | - [ ] `@*BobsPhone` 123 | - [ ] `stdout!("BobsPhone")` 124 | 125 | 126 | 127 | ### Упражнение 128 | 129 | ![This telephone game has a fork](telephoneFork.png) 130 | 131 | Давайте отойдем от линейной игры, где каждый передает сообщение следующему, и напишем вариант с ветвлением. В этот раз Боб отправит сообщение и Чарли, и ещё Элизе. 132 | Каждая ветвь может быть настолько длинной, насколько захотите, но в конце каждой ветви выведите сообщение на `stdout`. 133 | -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/03-TelephoneNamesAndProcesses/inverse.png -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/myNameIs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/03-TelephoneNamesAndProcesses/myNameIs.png -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/telephone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/03-TelephoneNamesAndProcesses/telephone.png -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/telephone3.rho: -------------------------------------------------------------------------------- 1 | new alice, bob, stdout(`rho:io:stdout`) in { 2 | // Start the game by sending a message to Alice 3 | alice!("How to program: Change stuff and see what happens.") 4 | | 5 | 6 | // Concurrently, Alice listens for the message 7 | for (message <- alice) { 8 | 9 | // When she receives the message she'll pass it on to Bob 10 | bob!(*message) 11 | } 12 | | 13 | 14 | // Concurrently, Bob will listens for the message 15 | for (message <- bob) { 16 | // Bob is the last player, so he'll announce the message 17 | stdout!(*message) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/telephoneChangedMessage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/03-TelephoneNamesAndProcesses/telephoneChangedMessage.png -------------------------------------------------------------------------------- /03-TelephoneNamesAndProcesses/telephoneFork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/03-TelephoneNamesAndProcesses/telephoneFork.png -------------------------------------------------------------------------------- /04-PersistentSendAndPeek/README.md: -------------------------------------------------------------------------------- 1 | # Persistent Sends and Peek 2 | 3 | ## Why send repeatedly? 4 | 5 | ![This radio navigation aid helps airplanes navigate by broadcasting the same message over and over](broadcasting.png) 6 | 7 | Our pizza and coffee shops were both interested in receiving many messages on the same reusable channel. We accomplished that with a persistent for `for (msg <= chan){...}` or a contract `contract chan(msg){...}`. 8 | 9 | An air traffic control tower may be interested in doing just the opposite -- sending the same message over and over. The controllers in the tower want to record a message containing weather and active runway information once, and make it available for every pilot who needs it. Like the pizza shop, they are busy and can't be bothered to continually re-send the message every time a pilot consumes it. 10 | 11 | 12 | 13 | ## Persistent send syntax 14 | 15 | The control tower just needs a minor adjustment in their code to make the send persistent. Rather than sending with a single `!`, they will use a double `!!`. 16 | 17 | [persistentSend.rho](persistentSend.rho) 18 | 19 | Confirm for yourself that the original send is still in the tuplespace. 20 | 21 | ### Exercise 22 | Modify the above code so that a second pilot also receives the information. Still, the send persists. 23 | 24 | By the way, did you notice that we don't need `new stdout(...) in {}` when we don't actually print anything to the screen `stdout`? 25 | 26 | How many comm events happen in `for (x <- y) {Nil} | y!!(Nil)` 27 | - [x] `1` 28 | - [ ] `many` 29 | - [ ] `0` 30 | 31 | 32 | ## Double Checking a Message 33 | 34 | Persistent sends and receives are very useful as we just showed. But often normal sends and receives are perfectly good too. Imagine that the air traffic controllers want to update the airport information when the weather changes. If they use a persistent send, they cannot make updates. 35 | 36 | A better solution is to use a normal send and require each pilot who receives the message to put it back on the channel when they are done. 37 | 38 | [putBack.rho](putBack.rho) 39 | 40 | ### Exercise 41 | Using what you already know, you can you can complete the code for an honest pilot to return the info to the `airportInfo` channel. 42 | 43 | Give that a try on your own first. The solution is listed below. 44 | 45 | 46 | How many comms happen in `for (x <= y) {Nil} | y!!(Nil)` 47 | - [ ] `1` 48 | - [x] `many` 49 | - [ ] `0` 50 | 51 | 52 | 53 | ## Peek Syntax 54 | One problem with the code above is that a forgetful pilot may not actually put the information back on the `airportInfo` channel causing problems for other pilots who need it. A better solution would be to not actually _receive_ the message off of the channel in the first place. 55 | 56 | ![Peeking at a message allows you to read it without consuming it.](letterPeek.png) 57 | 58 | Rholang will have a special syntax for this sort of thing eventually. It isn't available right now, but I'll show you the syntax just so you're ready. To "peek" at what's on a channel without consuming it, use the ` 15 | 16 | The problem is that the competitors can listen on the same channel Alice can. So what she really needs is for her fans to have a "write-only bundle" 17 | 18 | [fanmailPublish.rho](fanmailPublish.rho) 19 | 20 | The `bundle+ {*aliceFanMail}` is a channel just like `aliceFanMail` except it can only be sent on, not received. 21 | 22 | ## Subscriptions 23 | The bundle solution above does prevent Eve from stealing mail, which is good. But in the blockchain context it also has the unfortunate side effect that Alice has to pay to send her fanmail address. Blockchain fees work a little like postage. 24 | 25 | ![The sender includes a return envelope already posted to himself](returnEnvelope.png) 26 | 27 | ### Exercise 28 | 29 | Alice can save postage by making fans request the fanmail address from her. Then they will have to pay the transaction costs. A bit like sending a return envelope with a stamp already on it. 30 | 31 | Complete Alice's code so that she can get Bob the address he needs. 32 | 33 | Here's the answer: 34 | [fanmailAsk.rho](fanmailAsk.rho) 35 | 36 | 37 | Astute readers will notice that Eve can now just intercept messages asking for the fanmail address. Good observation. As a bonus exercise, you could write Eve's new code. (hint: it's the same as the old code). The solution to this problem involves public key cryptography and the registry. We'll learn about that later on. 38 | 39 | ### Exercise 40 | Our pizza shop back in lesson 2 had a similar problem to Alice. Rework that code so they can easily take on new customers. 41 | 42 | ## Jackpot 43 | 44 | ![A single "thrower" throws a ball for one of many catchers to catch](jackpot.png) 45 | 46 | I used to play a game called jackpot as a kid. One player would throw the ball and yell a number. The other players would all try to catch the ball and whoever caught it would receive that number of points. 47 | 48 | Playing jackpot is just the opposite of sending fanmail. Before there were many fans all sending to one celebrity. Now there is one thrower, sending to one of many recipients 49 | 50 | [jackpot.rho](jackpot.rho) 51 | 52 | Who will catch the ball in the jackpot code? 53 | - [ ] Bill because his catch code is first. 54 | - [ ] Bill because his catch code is closest to the throw code. 55 | - [ ] Paige because her catch code is last. 56 | - [x] We don't know; it is nondeterminate. 57 | 58 | 59 | ### Exercise 60 | Exercise: Use stdoutAck to display how many points each person actually gets when they catch the ball. 61 | 62 | 63 | 64 | 65 | How is this game in rholang different than the real game where one ball is thrown repeatedly? 66 | - [ ] It is a very accurate simulation 67 | - [x] In rholang all balls are thrown concurrently and caught in any order 68 | - [ ] In rholang the balls are caught in the reverse order from what they are thrown. 69 | - [ ] In rholang Bill makes all his catches, then Paige makes all her catches. 70 | 71 | 72 | ## Side Bar: String Operations 73 | Most programming languages will allow you to join or "concatenate" two strings together, and rholang is no exception. We can `stdout!("Hello " ++ "world")`, but we can't concatenate a string with an int. 74 | 75 | One solution is to use `stdoutAck` andsend acknowledgements. Another option is to print a list `stdout!(["Bill caught it. Points earned: ", *points])`. We'll go into more detail about both techniques in future lessons. 76 | 77 | A final option is to use string interpolation. String interpolation allows you to put placeholders into your strings and replace them with actual values using a map. 78 | 79 | [interpolation.rho](interpolation.rho) 80 | 81 | You can learn more about how the map that gets sets in lesson 12 on data structures. 82 | 83 | ## Imposter throws 84 | 85 | Notice that anyone can come along and mess up this game by throwing fake balls. This is just the opposite of Eve coming along and stealing Alice's fanmail. 86 | 87 | What code would Eve have to par in to throw an imposter ball worth 100 points? 88 | - [ ] for (imposter <- throw){imposter!(100)} 89 | - [x] throw!(100) 90 | - [ ] @"throw"!("100") 91 | 92 | 93 | We solve this problem by making sure that the public can only read from the throw channel, but not write to it. 94 | 95 | [jackpotPublish.rho](jackpotPublish.rho) 96 | 97 | Like before, this code requires the game host to pay for everyone who get's the bundle from him. It could be refactored so players have to subscribe to the game like we did with Alice and her fan mail. 98 | 99 | ## Public Key Crypto 100 | 101 | ![This bundle is sealed within the blockchain world, but totally openable to anyone outside. Remember that just because data is off limits within the blockchain, doesn't mean it's truly private.](privateNames.png) 102 | 103 | In some ways, read-only bundles duplicate the signing features of [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography). The jackpot catchers here are sure that the balls came from the thrower because only he can send on the throw channel, which is a lot like cryptographic signing. 104 | 105 | In some ways write-only bundles duplicate the encryption features of public-key cryptography. Only Alice can receive messages sent on her fan mail channel. One **very important difference** is that the messages sent here are 100% visible from outside the blockchain! So while write-only bundles are an effective way to communicate unforgeable names, they are not a good way to plot a heist, or evade government surveillance. **Be Careful!** 106 | 107 | ## More About Bundles 108 | 109 | In addition to read- and write-only bundles, there are two other types that are also useful. 110 | 111 | | Syntax | Can Read | Can Write | 112 | | ------ | -------- | --------- | 113 | | `bundle- {proc}` | YES | NO | 114 | | `bundle+ {proc}` | NO | YES | 115 | | `bundle0 {proc}` | NO | NO | 116 | | `bundle {proc}` | YES | YES | 117 | 118 | You may be wondering why a bundle on which you can neither send nor receive would ever be useful. Given what we've learned so far, that's a wonderful question. When we discuss pattern matching next unit, we'll see that bundles do more than restrict read- and write- capabilities. They also prevent taking compound names apart to look inside. 119 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/README_CN.md: -------------------------------------------------------------------------------- 1 | # Bundles 2 | 3 | ## 被盗取的信息 4 | 5 | ![Alice's fans love her and want to send her lots of mail .](Alice.png) 6 | 7 | Alice 是一个越来越出名的名人,她收到很多她粉丝的来信。她的粉丝们都是直接把信件发送到她的公共的"name"里。 8 | 9 | [fanmailBad.rho](fanmailBad.rho) 10 | 11 | 但是她变得越来越受欢迎,她嫉妒的竞争对手Eve开始盗取她的信件。 12 | 13 | ### 练习 14 | 写出竞争对手盗取信件的代码 15 | 16 | 现在的问题是竞争者可以监听Alice可以监听的相同的通道. 所有她真正需要的是有一个"只写的 bundle"给她的粉丝 17 | 18 | [fanmailPublish.rho](fanmailPublish.rho) 19 | 20 | `bundle+ {*aliceFanMail}` 像 `aliceFanMail` 一样是一个channel ,但是它只能用于发送,不能用于接收。 21 | 22 | ## 订阅 23 | 上面bundle的解决方案可以阻止Eve盗取信件,那是很好的。但是在区块链世界中,这样也是会有不好的效果因为Alice一定要为发送她的粉丝通道地址而付钱。 区块链的费用有点像邮资。 24 | 25 | ![The sender includes a return envelope already posted to himself](returnEnvelope.png) 26 | 27 | ### 练习 28 | Alice可以通过让粉丝请求她的粉丝邮箱地址来节省邮资。然后粉丝们一定要付这个钱。有点像发送一个已经带有邮票的信封回来。 29 | 30 | 完善 Alice的代码让她可以获得Bod需要的地址。 31 | 32 | 这里是答案: 33 | [fanmailAsk.rho](fanmailAsk.rho) 34 | 35 | 精明的读者已经注意到Eve可以通过请求粉丝邮箱地址来窃取信息。很好的观察力。作为一个额外的练习,你可以写出Eve的代码(提示:跟旧的一样)。这个问题的解决方法涉及公钥加密和注册。我们会在第四节学到。 36 | 37 | ### 练习 38 | 在我们第二课的披萨店有一个跟Alice相似的问题。重新编写代码,让他们可以容易地接收新客户。 39 | 40 | ## Jackpot 41 | 42 | ![A single "thrower" throws a ball for one of many catchers to catch](jackpot.png) 43 | 44 | 我以前小时候玩一个游戏叫Jackpot。一个人扔一个球然后说出一个数字。其他的人都会尝试去抓住那个球,无论谁抓住了那个球就可以获得那个数字的分数。 45 | 46 | 玩jackpot只是跟发送粉丝邮件正好相反。以前很多粉丝都发送邮件到明星。现在有一个发送者,发送给许多收件人中的一个。 47 | 48 | [jackpot.rho](jackpot.rho) 49 | 50 | 在jackpot代码中,谁会抓住那个球? 51 | - [ ] Bill因为他抓住球的代码最前。 52 | - [ ] Bill因为他抓住球的代码离抛球代码最近。 53 | - [ ] Paige因为他抓住球的代码最后面。 54 | - [x] 我们不知道。这是不确定的。 55 | 56 | 57 | ### 练习 58 | 练习: 当他们抓住球的时候,使用stdoutAck来显示每个人实际上的分数。 59 | 60 | 61 | 大多数程序语言都允许你组合或者"串联"两个字符串在一起,当然Rholang也不例外了。我们可以 `stdout!("Hello " ++ "world")`, 但是我们不能串联一个字符串和一个整型。那就是为什么我们要用`stdoutAck`这个方法。另一个方法就是打印一个列表 `stdout!(["Bill caught it. Points earned: ", *points])`。我们将在未来课程讨论更多关于这方面的细节。 62 | 63 | 在rholang里的这个游戏与现实中一个球不断重复抛有什么区别? 64 | - [ ] 是相当准确的模拟 65 | - [x] 在rholang中,所有球都只抛一次然后按顺序接住 66 | - [ ] 在rholang中球会按照他们被扔的相反顺序被接住 67 | - [ ] 在rholang中,Bill先会抓住球,然后到Paige抓住球 68 | 69 | 70 | ## 欺骗性的抛投 71 | 72 | 注意任何一个人都可以过来抛投一个假分数的球来把整个游戏弄乱。这就跟Eve去偷Alice粉丝信件的情况相反。 73 | 74 | Eve应该怎么样在代码中扔一个100分的欺骗的球? 75 | - [ ] for (imposter <- throw){imposter!(100)} 76 | - [x] throw!(100) 77 | - [ ] @"throw"!("100") 78 | 79 | 80 | 我们通过确定公众只能从抛投通道中进行读的操作来解决这个问题,公众不能进行写入。 81 | 82 | [jackpotPublish.rho](jackpotPublish.rho) 83 | 84 | 像以前一样,这个代码要求游戏主持人为所有从他获取bundle的人支付费用。我们可以重构代码让玩家需要订阅这个游戏就像Alice和她的粉丝邮箱。 85 | 86 | ## 公钥加密 87 | 88 | ![This bundle is sealed within the blockchain world, but totaly openable to anyone outside. Remember that just because data is off limits within the blockchain, doesn't mean it's truly private.](privateNames.png) 89 | 90 | 在某些方面上,只读的bundles就跟[公钥加密](https://en.wikipedia.org/wiki/Public-key_cryptography))的签名特性一样。 jackpot里面抓球的人要确定抛投人身份因为只有他可以在抛投通道发送,这种情况就像加密签名。 91 | 92 | 在某些方面上,只写的bundles就跟公钥加密的特性一样。只有Alice可以接受她粉丝邮箱通道里的信息。一个 **非常重要的不同** 是这里发送的信息在区块链中是100%透明的!所以即使只写的bundle对于不可伪造names是一种十分有效的通信方法,但是他们不是策划抢劫和逃避政府监控的好方法。 **一定要小心注意!** 93 | 94 | ## 更多Bundles 95 | 96 | 除了只写和只读bundles,还有另外两种形式的bundles。另外的bundle类型比较少见但是也是有用的。我们将会在有需要的时候再探索他们,但是我们这里先简短地总结他们。 97 | 98 | | 语法 | 可读 | 可写 | 99 | | ------ | -------- | --------- | 100 | | `bundle- {proc}` | YES | NO | 101 | | `bundle+ {proc}` | NO | YES | 102 | | `bundle0 {proc}` | NO | NO | 103 | | `bundle {proc}` | YES | YES | 104 | 105 | 你可能想知道为什么一个bundle 既不能发送也不能接受有什么用。根据我们现在所学到的,那是一个很好的问题。当我们在下一单元讨论模式匹配,我们就可以看到bundles可以做更严格的读写功能。它们也可以阻止把组合names分开然后看里面的内容。 106 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/fanmailAsk.rho: -------------------------------------------------------------------------------- 1 | new alice, bob, eve, stdout(`rho:io:stdout`) in { 2 | 3 | // Alice get a lot of fan mail, so she 4 | // creates a new write only bundle and publishes it. 5 | new aliceFanMail in { 6 | 7 | // Alice returns fanmail channel to any fan that asks 8 | for (return <= alice) { 9 | return!(bundle+ {*aliceFanMail}) 10 | } 11 | | 12 | 13 | // Alice also reads fan mail 14 | for (mail <- aliceFanMail) { 15 | stdout!("Alice received a fanmail") 16 | } 17 | } 18 | | 19 | 20 | // When Bob wants to send fanmail he asks for the channel 21 | // and then sends 22 | new return in { 23 | alice!(*return) | 24 | for (aliceFanMail <- return) { 25 | aliceFanMail!("Dear Alice, you're #TheBest") 26 | } 27 | } 28 | | 29 | 30 | // Eve tries to intercept a message, but cannot 31 | // because Alice's channel is write-only 32 | new return in { 33 | alice!(*return) | 34 | for (aliceFanMail <- return) { 35 | for (@stolenMail <= aliceFanMail) { 36 | stdout!(["Eve stole a message: ", stolenMail]) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/fanmailBad.rho: -------------------------------------------------------------------------------- 1 | new alice, stdout(`rho:io:stdout`) in { 2 | // Alice reads fan mail 3 | for (mail <- alice) { 4 | stdout!("Alice received a fanmail") 5 | } 6 | | 7 | 8 | // Bob sends fan mail 9 | alice!("Dear Alice, you're #TheBest") 10 | } 11 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/fanmailEve.rho: -------------------------------------------------------------------------------- 1 | for (@stolenMail <= alice) { 2 | stdout!("Eve stole a message") 3 | } 4 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/fanmailPublish.rho: -------------------------------------------------------------------------------- 1 | new alice, bob, eve, stdout(`rho:io:stdout`) in { 2 | 3 | // Alice gets a lot of fan mail, so she 4 | // creates a new write only bundle and publishes it. 5 | new aliceFanMail in { 6 | 7 | // Alice gives fanmail channel publicly 8 | alice!!(bundle+ {*aliceFanMail}) 9 | | 10 | 11 | // Alice also reads fan mail 12 | for (mail <= aliceFanMail) { 13 | stdout!("Alice received a fanmail") 14 | } 15 | } 16 | | 17 | 18 | // When Bob wants to send fanmail he asks for the channel 19 | // and then sends 20 | for (aliceFanMail <- alice) { 21 | aliceFanMail!("Dear Alice, you're #TheBest") 22 | } 23 | | 24 | 25 | // Eve tries to intercept a message, but cannot 26 | // because Alice's fanmail channel is write-only 27 | for (aliceFanMail <- alice) { 28 | for (@stolenMail <= aliceFanMail) { 29 | stdout!(["Eve stole a message: ", stolenMail]) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/interpolation.rho: -------------------------------------------------------------------------------- 1 | new stdout(`rho:io:stdout`), printStuff in { 2 | 3 | printStuff!({"noun": "person", "adverb": "sideways"}) | 4 | 5 | contract printStuff(map) = { 6 | stdout!("The ${noun} jumped ${adverb}" %% *map) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/jackPotNicePrinting.rho: -------------------------------------------------------------------------------- 1 | for (points <= @throw){ 2 | new ack in { 3 | stdoutAck!("Bill caught it. Points earned: ", *ack) 4 | | 5 | for( _ <- ack){ 6 | stdout!(*points) 7 | } 8 | } 9 | } 10 | // Do the same for Paige 11 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/jackpot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/07-BundlesAndInterpolation/jackpot.png -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/jackpot.rho: -------------------------------------------------------------------------------- 1 | new throw, stdout(`rho:io:stdout`) in { 2 | // Throw the ball worth five points 3 | throw!(5) 4 | | 5 | 6 | // Throw the ball several more times 7 | throw!(4) | 8 | throw!(2) | 9 | throw!(6) | 10 | 11 | // Bill and Paige both try to catch 12 | for (points <= throw){ 13 | stdout!("Bill caught it") 14 | } 15 | | 16 | for (points <= throw){ 17 | stdout!("Paige caught it") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/jackpotPublish.rho: -------------------------------------------------------------------------------- 1 | new gameCh, stdout(`rho:io:stdout`) in { 2 | new throw in { 3 | 4 | //Give out read-only access 5 | gameCh!!(bundle- {*throw}) 6 | | 7 | // Now actually make all the throws 8 | throw!(4) | 9 | throw!(2) | 10 | throw!(6) 11 | } 12 | | 13 | // Bill and Paige join the game 14 | for (throw <- gameCh){ 15 | for (points <= throw){ 16 | stdout!(["Bill caught it. Points: ", *points]) 17 | } 18 | } 19 | | 20 | // Eve tries to throw a fake, but can't 21 | for (throw <- gameCh){ 22 | throw!(100) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/privateNames.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/07-BundlesAndInterpolation/privateNames.png -------------------------------------------------------------------------------- /07-BundlesAndInterpolation/returnEnvelope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/07-BundlesAndInterpolation/returnEnvelope.png -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/README.md: -------------------------------------------------------------------------------- 1 | # State Channels 2 | 3 | ## Holding on to data 4 | 5 | ![Variables are so 2015. It's all about state channels now.](variables.png) 6 | 7 | By now you're good at sending data to the tuplespace, and receiving data from the tuplespace. But whenever you're computing, you occasionally need to set data aside to be used later. Almost every programming language has a concept of variables. 8 | 9 | Another way in which rholang is unique is that it doesn't have traditional variables. Instead, we can just use the tuplespace to store our data. Whenever you want to set something aside for later, just send it on some channel and receive it back later. Channels that are used in this way are called "state channels", and often have `Ch` at the end of their name 10 | 11 | [box.rho](box.rho) 12 | 13 | 14 | What data gets sent to `@somePublicChannel`? 15 | - [ ] 0 16 | - [ ] box 17 | - [x] 42 18 | - [ ] It is empty 19 | 20 | 21 | What data is left in the `boxCh` state channel? 22 | - [ ] 0 23 | - [ ] @"somePublicBox" 24 | - [ ] 42 25 | - [x] It is empty 26 | 27 | 28 | ## Persisting Data 29 | If we were to check the box again, we would not get a result. Because once we receive the message, it gets consumed from the tuplespace. We briefly discussed the solution back in our lesson on persistent sends and peeks. 30 | 31 | [persistentBox.rho](persistentBox.rho) 32 | 33 | What data gets sent to `@somePublicChannel`? 34 | - [ ] 0 35 | - [ ] box 36 | - [x] 42 37 | - [ ] It is empty 38 | 39 | 40 | What data is left in the `boxCh` state channel? 41 | - [ ] 0 42 | - [ ] @"somePublicBox" 43 | - [x] 42 44 | - [ ] It is empty 45 | 46 | 47 | ## Patience Game Revisited 48 | A few lessons back we discussed the patience game, where each player hopes to be the last one to send a message to the contract. We had some problems back then because we couldn't guarantee that a result of the game would ever be output. 49 | 50 | Take a minute to remind yourself of the problem we had. With a state channel, we can solve this problem properly. 51 | 52 | [patience.rho](patience.rho) 53 | 54 | How does the above code avoid the problem of each block getting called once? 55 | - [ ] By forcing player one to use the top block 56 | - [x] Because after the first call `activeCh` is empty 57 | - [ ] Because state channel make things sequential 58 | 59 | ## Objects and Methods 60 | ![This click-counter can be incremented and reset](clickCounter.png) 61 | 62 | In "Object Oriented Programming" languages such as java, we can model real-world objects by encapsulating some data along with methods that use or change the data. The same thing is possible in rholang. 63 | 64 | In this example, we'll create an object that represents a basic click counter. The ingredients are: 65 | * State Channels: currentCount 66 | * Methods: increase, reset 67 | 68 | [counter.rho](counter.rho) 69 | 70 | ### Exercises 71 | It is inconvenient to manually replace the counter value each time I check it. Instead we should have a method for that. 72 | 73 | 74 | 75 | 76 | ### Exercise 77 | Now that it's easier and safer to check the counter, let's write some better tests that actually check all the methods. 78 | 79 | 80 | 81 | ## Factories 82 | If you've programmed in other languages like java you may be familiar with constructors. If you haven't programmed in in java, that's great, because Rholang uses factories to make new objects rather than constructors. 83 | 84 | The counter is a useful construct in rholang, and you'll likely find that you use it in your projects. The problem is that many projects may want to use counters, and having just one is insufficient. So the solution is to make a factory contract that makes counters. When the factory contract is called, it sends back a brand new counter. 85 | 86 | [counterFactory.rho](counterFactory.rho) 87 | 88 | How would a user call the factory to get a new counter? 89 | - [ ] `counterFactory!(*ack)` 90 | - [ ] `counterFactory!(0, *ack)` 91 | - [ ] `@"counterFactory"()` 92 | - [x] `counterFactory!(myIncrease, myReset)` 93 | 94 | How would a user reset their counter after creating as indicated above. 95 | - [ ] `myIncrease!(*ack)` 96 | - [x] `myReset!(*ack)` 97 | - [ ] `counterFactory!(myReset, *ack)` 98 | - [ ] `counterFactory!(myReset)` 99 | 100 | 101 | 102 | ## Method Dispatching 103 | There are two primary techniques for making methods available. The first option I call "separation of powers" because each method listens on its own dedicated channel. 104 | 105 | Another option is the "control panel" technique where there is a single unforgeable name called the control panel and all the methods are built on it. 106 | 107 | ``` 108 | // Separation of Powers 109 | contract factory(method1, method2) = { 110 | contract method1(ack) = { ... } 111 | contract method2(ack) = { ... } 112 | } 113 | 114 | // Control Panel 115 | contract factory(cPanel) = { 116 | contract @[cPanel, "method1"](ack) = { ... } 117 | contract @[cPanel, "method2"](ack) = { ... } 118 | } 119 | ``` 120 | 121 | Which technique did the counter example use to dispatch methods? 122 | - [x] Separation of Powers 123 | - [ ] Control Panel 124 | 125 | ### Exercise 126 | Convert the counter example to use the other method dispatching technique. You should convert the tests too. 127 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/README_CN.md: -------------------------------------------------------------------------------- 1 | # 状态通道 2 | 3 | ## 保存数据 4 | 5 | ![Variables are so 2015. It's all about state channels now.](variables.png) 6 | 7 | 到现在为止,你已经很擅长于发送数据到元组空间和从元组空间中获取数据。但是无论你在什么时候进行计算,你有时需要把一些数据放在一边晚点才使用。几乎所有编程语言都有变量的概念。 8 | 9 | rholang 的另一个独特的地方在于它没有传统的变量。然而,我们只是使用元组空间来保存我们的数据。只要你想要把一些数据放在一边晚点使用,就把数据发送到一些通道里然后晚点再从通道中获取。以这种方式使用的通道叫做"状态通道",通常我们会在状态通道名字末尾用`Ch` 10 | 11 | [box.rho](box.rho) 12 | 13 | 14 | 什么数据发送到`@somePublicChannel`中? 15 | - [ ] 0 16 | - [ ] box 17 | - [x] 42 18 | - [ ] 它里面是空的 19 | 20 | 21 | 什么数据留在了`boxCh` 状态通道里? 22 | - [ ] 0 23 | - [ ] @"somePublicBox" 24 | - [ ] 42 25 | - [x] 它里面是空的 26 | 27 | 28 | ## 持久化数据 29 | 如果我们再次检查通道,我们会得不到数据。因为一旦我们接收了信息,信息就会从元组空间中取出。我们在上面的课程简短地讨论过解决方案。 30 | 31 | [persistentBox.rho](persistentBox.rho) 32 | 33 | 什么数据发送到`@somePublicChannel`中? 34 | - [ ] 0 35 | - [ ] box 36 | - [x] 42 37 | - [ ] 它里面是空的 38 | 39 | 40 | 什么数据保留在` boxCh `状态通道里? 41 | - [ ] 0 42 | - [ ] @"somePublicBox" 43 | - [x] 42 44 | - [ ] 它里面是空的 45 | 46 | 47 | ## 重访耐心游戏 48 | 在几节课钱,我们讨论了一个耐心游戏,游戏里的玩家希望成为最后一个人发送信息到合约里面。之前我们遇到了一些问题因为我们无法保证游戏的结果能输出。 49 | 50 | 花几分钟重新看看想想我们之前遇到的问题。现在使用这个状态通道,我们可以适当地解决这个问题。 51 | 52 | [patience.rho](patience.rho) 53 | 54 | 上面的代码是如何解决每一块代码只调用一次的问题? 55 | - [ ] 通过强制玩家1使用顶部的代码 56 | - [x] 因为在第一次调用后,`activeCh` 是空的 57 | - [ ] 因为状态通道使代码顺序执行 58 | 59 | ## 对象和方法 60 | ![This click-counter can be incremented and reset](clickCounter.png) 61 | 62 | 在如Java这样的"面向对象编程" 语言, 我们可以通过封装一些使用的数据和修改数据的方法到真实世界的对象上建立模型。在rholang里面同样的事情也是可能的。 63 | 64 | 在这个例子里面,我们会创建一个对象代表一个基本的点击计数器。需要的部件有: 65 | * 状态通道:当前计数 66 | * 方法:增加,重置 67 | 68 | [counter.rho](counter.rho) 69 | 70 | ### 练习 71 | 如果每次检查时,都要我手动更换计数值会是很不方便的。取而代之的我们应该有一个方法做那个事。 72 | 73 | 74 | 75 | 76 | ### 练习 77 | 现在更加简单和安全地去检查计数器。让我们一些更好的测试来测试所有的方法。 78 | 79 | 80 | 81 | ## 工厂 82 | 如果你曾经用其它像Java这样的语言,那你可能会很熟悉构造器。如果你曾经用过Java,那非常好,因为rholang 用工厂来创建新的对象而不是构造器。 83 | 84 | 在rholang中创造一个计数器是很有用的,你将来很可能会在你的项目中用到。现在的问题是很多项目都可能使用计数器,只有一个可能是不足够的。所以解决方法是创建一个工厂合约创建计数器。当一个工厂合约被调用,它会返回一个新的计数器。 85 | 86 | [counterFactory.rho](counterFactory.rho) 87 | 88 | 用户怎么调用工厂才可能得到一个新的计数器? 89 | - [ ] `counterFactory!(*ack)` 90 | - [ ] `counterFactory!(0, *ack)` 91 | - [ ] `@"counterFactory"()` 92 | - [x] `counterFactory!(myIncrease, myReset)` 93 | 94 | 如果用户按照上面方法创造一个计数器,用户怎么重置他们的计数器。 95 | - [ ] `myIncrease!(*ack)` 96 | - [x] `myReset!(*ack)` 97 | - [ ] `counterFactory!(myReset, *ack)` 98 | - [ ] `counterFactory!(myReset)` 99 | 100 | 101 | 102 | ## 方法调度 103 | 这里有两种主要的技术使方法可用。第一种方法我称为"方法独立" 因为每一个方法都监听它们自己专用的通道。 104 | 105 | 另一种方法是"控制面板" 技术, 这技术会用一个单独的不可伪造name做一个叫做控制面板的东西,然后所有方法都在此基础上建立。 106 | 107 | ``` 108 | // Separation of Powers 109 | contract factory(method1, method2) = { 110 | contract method1(ack) = { ... } 111 | contract method2(ack) = { ... } 112 | } 113 | 114 | // Control Panel 115 | contract factory(cPanel) = { 116 | contract @[cPanel, "method1"](ack) = { ... } 117 | contract @[cPanel, "method2"](ack) = { ... } 118 | } 119 | ``` 120 | 121 | 计数器示例使用哪种技术来调度方法? 122 | - [x] 方法独立 123 | - [ ] 控制面板 124 | 125 | ### 练习 126 | 用另一种调度方法来转换上面的例子。你也应该把测试也转换了。 127 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/box.rho: -------------------------------------------------------------------------------- 1 | new stdout(`rho:io:stdout`), boxCh in { 2 | // To save data we just put it in the box 3 | boxCh!(42) 4 | | 5 | 6 | // Then to get data back out 7 | for (data <- boxCh) { 8 | // Do whatever you want with the data here. 9 | stdout!(*data) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/checkMethod.rho: -------------------------------------------------------------------------------- 1 | // Method to check the counter 2 | contract check(return) = { 3 | for(count <- currentCount){ 4 | currentCount!(*count) | 5 | return!(*count) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/clickCounter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/08-StateChannelsAndMethods/clickCounter.png -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/counter.rho: -------------------------------------------------------------------------------- 1 | new currentCount, increase, reset, check, stdout(`rho:io:stdout`) in { 2 | 3 | // Starting the counter at 0 4 | currentCount!(0) | 5 | 6 | // Method to increase counter (returns the old value) 7 | contract increase(ack) = { 8 | for(old <- currentCount) { 9 | currentCount!(*old + 1) | 10 | ack!(*old) 11 | } 12 | } | 13 | 14 | // Method to reset the counter (returns the old value) 15 | contract reset(ack) = { 16 | for(old <- currentCount) { 17 | currentCount!(0) | 18 | ack!(*old) 19 | } 20 | 21 | } | 22 | 23 | // Increase the value three times 24 | new ack in { 25 | increase!(*ack) | 26 | for(_ <- ack) { 27 | increase!(*ack) | 28 | for(_ <- ack) { 29 | increase!(*ack) | 30 | for(_ <- ack) { 31 | increase!(*ack) | 32 | 33 | // And check it's value afterwards 34 | for(_ <- ack; count <- currentCount) { 35 | stdout!(*count) 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/counterFactory.rho: -------------------------------------------------------------------------------- 1 | new counterFactory, stdout(`rho:io:stdout`) in { 2 | contract counterFactory(increase, reset) = { 3 | new currentCount in { 4 | // Start the counter at zero 5 | currentCount!(0) | 6 | 7 | // Method to increase counter (returns the old value) 8 | contract increase(ack) = { 9 | for (old <- currentCount) { 10 | currentCount!(*old + 1) | 11 | ack!(*old) 12 | } 13 | } 14 | | 15 | 16 | // Method to reset the counter (returns the old value) 17 | contract reset(ack) = { 18 | for(old <- currentCount){ 19 | currentCount!(0) | 20 | ack!(*old) 21 | } 22 | } 23 | } 24 | } 25 | | 26 | 27 | new ack, myIncrease, myReset in { 28 | // Demo using the counter here 29 | Nil 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/counterTests.rho: -------------------------------------------------------------------------------- 1 | new ack in { 2 | // This gets deeply nested because it's sequential. 3 | // This indentation style keeps it readable 4 | increase!(*ack) | for(_ <- ack) { 5 | 6 | check!(*ack) | for(count <- ack) { 7 | stdoutAck!(*count, *ack) | for(_ <- ack) { 8 | 9 | increase!(*ack) | for(_ <- ack) { 10 | 11 | check!(*ack) | for(count <- ack) { 12 | stdoutAck!(*count, *ack) | for(_ <- ack) { 13 | 14 | reset!(*ack) | for(count <- ack) { 15 | 16 | check!(*ack) | for(count <- ack) { 17 | stdout!(*count) 18 | 19 | }}}}}}}} 20 | } 21 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/patience.rho: -------------------------------------------------------------------------------- 1 | new P1, P2, stdout(`rho:io:stdout`) in { 2 | 3 | // active gets its own scope so players can't change its value. 4 | new active in { 5 | active!(true) 6 | | 7 | for(_ <- active; _ <- P1) { 8 | for( _ <- P2) { 9 | stdout!("P2 Wins") 10 | } 11 | } 12 | | 13 | for(_ <- active; _ <- P2) { 14 | for (_ <- P1) { 15 | stdout!("P1 Wins") 16 | } 17 | } 18 | } 19 | | 20 | P1!(Nil) 21 | | 22 | P2!(Nil) 23 | } 24 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/persistentBox.rho: -------------------------------------------------------------------------------- 1 | new boxCh in { 2 | // To save data we just put it in the box 3 | boxCh!(42) 4 | | 5 | 6 | // To check the value without consuming it 7 | for (data <- boxCh) { 8 | // We send a copy back to the box 9 | boxCh!(*data) 10 | | 11 | // The do whatever with it 12 | @"somePublicChannel"!(*data) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /08-StateChannelsAndMethods/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/08-StateChannelsAndMethods/variables.png -------------------------------------------------------------------------------- /09-ObjectCapabilities/README.md: -------------------------------------------------------------------------------- 1 | # Object Capabilities 2 | 3 | Recently we learned how unforgeable names can restrict the use of a channel to those who know the name. We've also see how state channels can be used to store data and methods can be used to modify encapsulated data. In this lesson we'll see how methods that are placed on unforgeable names lead to a tremendously useful design pattern known as "object capabilities". 4 | 5 | ![Good thing I didn't lose my car capabilities, I mean car keys in that freezer](keys.png) 6 | 7 | An everyday example of an object capability is the key to your home or car. Possessing the object gives you the capability to enter the home or start the car. With object you also have the ability to delegate by giving to key or a copy of the key to someone else. 8 | 9 | In this lesson we'll build up a few example projects that uses state channels, and object capabilities. We'll see that object capabilities can be used more generally than bundles to grant permissions such as reading and writing data, but also more abstract capabilities like reseting a counter or deleting a facebook account. 10 | 11 | ## ATC Revisited 12 | Let's revisit the air traffic control example from lesson 4. Previously controllers were able to broadcast weather and runway information by using a repeated send. But they were not able to update the information. And we all know weather can change unpredictably. So in this example we'll store the current information on a state channel, and give the controllers a capability to update it as necessary. 13 | 14 | [atc.rho](atc.rho) 15 | 16 | It may seem natural to use a read-only bundle for tuning into the station. However, if we use a bundle, then the first listener to receive the message, would consume it from the state channel. It wouldn't be left for other pilots to receive. In order to ensure that the message is persisted like we want, we handle all access to the state channel ourselves, and only give the pilots a capability to query for the the correct message. 17 | 18 | How would the ATCs update the information? 19 | - [x] `set!("Strong crosswinds, be advised")` 20 | - [ ] `setInfo!("Strong crosswinds, be advised")` 21 | - [ ] `getInfo!("Strong crosswinds, be advised")` 22 | - [ ] `stationFactory.setInfo!("Strong crosswinds, be advised")` 23 | 24 | ### Exercise 25 | Write more thorough tests to make sure the ATCs can update the status successfully, and that pilots cannot 26 | 27 | ## Savings Account 28 | In this example we'll write code to model a simple savings account in rholang. It will have deposit, withdraw, and check methods. 29 | 30 | Unlike with our counter, a savings account needs to be secure. We don't want just anyone knowing our balance, or worse, withdrawing it. 31 | 32 | Here is some starter code to consider 33 | [savingsStarter.rho](savingsStarter.rho) 34 | 35 | ### Exercise 36 | Fill in the remaining methods in the account. 37 | 38 | Which contract serves as a factory? 39 | - [ ] `check` 40 | - [ ] `withdraw` 41 | - [ ] `deposit` 42 | - [x] `openAccount` 43 | 44 | Our current savings account allows negative balances, but probably it shouldn't. Think about how you might try to solve that issue. We'll learn the proper tool to do that in our next lesson. 45 | 46 | ## Stealing Funds 47 | Try to write the code Eve would need to par in to steal Sarah's funds. I bet you can't think of any. That's because only Sarah has access to the unforgeable names that control the account. 48 | 49 | 50 | If Sarah wanted to allow her friend Stephanie to deposit into her bank account, but not check or withdraw, what code should she run? 51 | - [ ] `stephanie!(*sarahWithdraw)` 52 | - [x] `stephanie!(*sarahDeposit)` 53 | - [ ] `sarahWithdraw!("enable", *stephanie)` 54 | - [ ] `openAccount!(10, *sarahDeposit, @"sarahWithdraw", @"sarahCheck")` 55 | 56 | 57 | 58 | 59 | ## Two Kinds of Factories 60 | So far all of our factory methods have required us to pass in names on which to build the contracts. In the savings account example, those names were `check`, `deposit`, and `withdraw`. I call this a "BYOC" or "bring your own channel" factory. The BYOC technique has the advantage that the user can supply any names she likes including names she got from other contracts or public names. 61 | 62 | Another technique is to allow the factory to create the necessary unforgeable names and send them back to the caller. I call this the a "full service" factory. If you don't require the flexibility of passing in arbitrary names, a full service factory is often less hassle. 63 | 64 | ### Exercise 65 | Convert the savings account from byoc factory to to full service factory. 66 | 67 | Now that you've converted the savings account, is it still possible for Sarah to make her deposit capability public? 68 | - [ ] No; she can no longer pass in a public name 69 | - [ ] No; she doesn't have access to do so 70 | - [x] Yes; she just needs to make the new capability public herself 71 | - [ ] Yes; just like before 72 | 73 | 74 | ## Abortable Rocket Launch 75 | Back when we first learned the join operator we considered a scenario in which two operators must both give clearance to launch a rocket. We desired that they should also be able to retract the clearance. 76 | 77 | This problem can be solved by giving the operator an abort button when they give their launch command. 78 | 79 | [abortableLaunch.rho](abortableLaunch.rho) 80 | 81 | ### Exercise 82 | Complete the above code with bob's launch logic and integration tests. 83 | 84 | ## Design Patterns 85 | There are many common Object Capability design patterns. Many of the are explained and illustrated in [A Picturebook of Secure Cooperation](http://erights.org/talks/efun/SecurityPictureBook.pdf) 86 | 87 | ### Exercise 88 | We will encounter many of these patterns as we work through the upcoming examples, but I encourage you to implement one or two of them in rholang right now. 89 | -------------------------------------------------------------------------------- /09-ObjectCapabilities/README_CN.md: -------------------------------------------------------------------------------- 1 | # 对象功能 2 | 3 | 最近我们学习了如何用不可伪造的"names"来限制知道这个"name"的人来使用这个通道。我们也见识了如何用状态通道来保存数据,还有如何用将方法用于修改封装数据。在这节课中,我们将会学习如何将方法放置在不可伪造的"name"上,设计出一种非常有用的设计模式--“对象功能”。 4 | 5 | ![Good thing I didn't lose my car capabilities, I mean car keys in that freezer](keys.png) 6 | 7 | 对象功能的日常例子就是你家或者车的钥匙。你可以通过使用这个对象的功能来进入你的家里或者启动你的汽车。你也可以通过给予你的钥匙或者你钥匙的复制品给别人,让别人也拥有那些功能。 8 | 9 | 在这一节课中,我们将会使用状态通道和对象功能来创建一些例子工程。我们可以看到对象功能比bundle赋予读写数据权利的方式更常用,还可以使用更抽象的功能如重置计数器或者删除一个facebook账户。 10 | 11 | ## 重访空中交通管制塔 12 | 让我们现在再看一下第四课的空中交通管制的例子。先前的控制者可以通过使用一个持续性的发送来广播天气和跑道信息。但是他们不能够更新信息。我们都知道天气是经常无法预测地变化。所以在这个例子中,我们将要保存现在的信息在状态通道里面,然后给控制者一个功能来按需要更新信息。 13 | 14 | [atc.rho](atc.rho) 15 | 16 | 使用一个只读的bundle来调整到站里似乎更加自然。然而,如果我们使用budle,然后第一个接收信息的监听者可能会取出在状态通道的信息。然后就不能给其它飞行员接收这个信息。为了能确保消息可以按我们想的那样持久化,我们要处理所有到状态通道的权限,然后只能给飞行员去获取正确信息的功能。 17 | 18 | 空中交通管制是如何跟新信息的? 19 | - [x] `set!("Strong crosswinds, be advised")` 20 | - [ ] `setInfo!("Strong crosswinds, be advised")` 21 | - [ ] `getInfo!("Strong crosswinds, be advised")` 22 | - [ ] `stationFactory.setInfo!("Strong crosswinds, be advised")` 23 | 24 | ### 练习 25 | 写更多全面的测试以确保空中交通管制可以成功地更新信息而飞行员不可以。 26 | Write more thorough tests to make sure the ATCs can update the status successfully, and that pilots cannot 27 | 28 | ## 储蓄账户 29 | 在这个例子里,我们要用rholang写代码来模拟一个简单的储蓄账户。它有存入,提取和查看的方法。 30 | 31 | 不想我们的计数器,储蓄账户必需要安全的。我们也不想其他人知道我们有多少钱,更不想别人能拿我们的钱。 32 | 33 | 这里是一些需要考虑的初步的代码。 34 | [savingsStarter.rho](savingsStarter.rho) 35 | 36 | ### 练习 37 | 在账户代码里把剩下的方法代码补上。 38 | 39 | 下面哪个合约是被当做工厂的? 40 | - [ ] `check` 41 | - [ ] `withdraw` 42 | - [ ] `deposit` 43 | - [x] `openAccount` 44 | 45 | 我们当前的储蓄账户允许负的存款,但是可能它不应该这样的。请想一想你应该怎么去解决这个问题。我们将会在下一节课学习一样合社的工具来完成这个事。 46 | 47 | ## 盗取资金 48 | 尝试写出Eve需要盗取Sarah资金的代码。我敢打赌你想不出任何方法。因为只有Sarah有权限使用控制账户的不可伪造的"name"。 49 | 50 | 51 | 如果Sarah想要允许别人存钱到她的银行账户,但是不可以查看和提取,她应该怎么创建她的账户? 52 | - [ ] `openAccount!(10, *"sarahDeposit", *sarahWithdraw, *sarahCheck)` 53 | - [x] `openAccount!(10, @"sarahDeposit", *sarahWithdraw, *sarahCheck)` 54 | - [ ] `openAccount!(10, @"sarahDeposit", @"sarahWithdraw", @"sarahCheck")` 55 | - [ ] `openAccount!(10, *sarahDeposit, @"sarahWithdraw", @"sarahCheck")` 56 | 57 | 58 | 59 | 60 | ## 两种工厂 61 | 到目前为止,我们所有的工厂方法都要求我们传入“names”来创建合约。在储蓄账户的例子中,这些"names"是 `check`, `deposit` 和 `withdraw`。我把这种工厂叫做“自我创建”工厂,简称"BYOC"。这种BYOC技术有一个优势,就是用户可以提供任何她喜欢的从别的合约来的或者公共的"names"。 62 | 63 | 另一种技术是允许工厂创建需要的不可伪造的"names"然后发送给回调的人。我把这种方式成为“全面服务”工厂。如果你不要求有灵活传入随意"names"的功能,一个全面服务的工厂可能更不麻烦。 64 | 65 | ### 练习 66 | 把例子中的工厂模式转化为另一种模式 67 | 68 | 69 | 现在你已经装换了储蓄账户的代码,Sarah还有可能让别人给她的账户存款么? 70 | - [ ] 不可以;她不再可以传入一个公共的“name” 71 | - [ ] 不可以;她没有权利这么做 72 | - [x] 可以;她只需要自己把新的功能公开。 73 | - [ ] 可以;就像以前一样 74 | 75 | 76 | ## 可中止的火箭发射 77 | 回到我们学到join操作的时候,我们假想了一个情况,两个操作员必须同时许可火箭发射。我们希望他们也可以收回发射许可。 78 | 79 | 这个问题的解决方法是,当他们允许火箭发射的时候,可以给操作员一个中止按钮。 80 | 81 | [abortableLaunch.rho](abortableLaunch.rho) 82 | 83 | ### 练习 84 | 完成上面代码中bob的发射逻辑并且测试。 85 | 86 | ## 设计模式 87 | 还有很多常用的对象功能设计模式。你可以在[A Picturebook of Secure Cooperation](http://erights.org/talks/efun/SecurityPictureBook.pdf)中找到很多例子解释说明。 88 | 89 | ### 练习 90 | 我们会在以后遇到的例子中遇到很多这样的设计模式,但是我鼓励你尝试自己用rholang实现1到2个。 91 | -------------------------------------------------------------------------------- /09-ObjectCapabilities/abortableLaunch.rho: -------------------------------------------------------------------------------- 1 | new rocketFactory in { 2 | 3 | // When a new rocket is setup, a launch capability for each for each operator is passed in 4 | contract rocketFactory(aliceLaunch, bobLaunch, ack) = { 5 | new aliceReadyCh, bobReadyCh in { 6 | // Start out neither ready 7 | aliceReadyCh!(false)| 8 | bobReadyCh!(false)| 9 | 10 | contract aliceLaunch(ack) = { 11 | new aliceAbort in { 12 | for (_ <- aliceReadyCh) { 13 | aliceReadyCh!(true) 14 | } 15 | | 16 | contract aliceAbort(ack) = { 17 | for(_ <- aliceReadyCh) { 18 | aliceReadyCh!(false) 19 | | 20 | ack!(Nil) 21 | } 22 | } 23 | | 24 | ack!(*aliceAbort) 25 | } 26 | } 27 | | 28 | Nil // Bob contract goes here 29 | | ack!(Nil) 30 | } 31 | } 32 | | 33 | // Make a new rocket to test 34 | new aliceLaunch, bobLaunch, ack in { 35 | rocketFactory!(*aliceLaunch, *bobLaunch, *ack)| 36 | for (_ <- ack){ 37 | Nil // Tests go here 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /09-ObjectCapabilities/atc.rho: -------------------------------------------------------------------------------- 1 | 2 | new stationFactory, stdout(`rho:io:stdout`) in { 3 | contract stationFactory(initialMessage, getInfo, setInfo) = { 4 | new currentMessage in { 5 | // Populate the initial message 6 | currentMessage!(*initialMessage) 7 | | 8 | 9 | // Owner can update the message anytime 10 | contract setInfo(newMessage) = { 11 | for (msg <- currentMessage) { 12 | currentMessage!(*newMessage) 13 | } 14 | } 15 | | 16 | 17 | // User tunes in for latest message 18 | contract getInfo(return) = { 19 | for (msg <- currentMessage){ 20 | return!(*msg) 21 | | 22 | currentMessage!(*msg) 23 | } 24 | } 25 | } 26 | } 27 | | 28 | 29 | // Controllers create new station with private set capability 30 | // and public get capability 31 | new airportInfo, set in { 32 | stationFactory!("Weather is nice", *airportInfo, *set) 33 | } 34 | | 35 | // Listener tunes in to receive latest message 36 | airportInfo!(*stdout) 37 | } 38 | -------------------------------------------------------------------------------- /09-ObjectCapabilities/savingsStarter.rho: -------------------------------------------------------------------------------- 1 | new openAccount in { 2 | // This contract registers a new account and creates its methods. 3 | contract openAccount(initialDeposit, deposit, withdraw, check) = { 4 | new balanceCh in { 5 | balanceCh!(*initialDeposit) 6 | | 7 | 8 | // Withdraw Contract 9 | contract withdraw(amount, ack) = { 10 | for (old <- balanceCh) { 11 | balanceCh!(*old - *amount) | 12 | ack!(Nil) 13 | } 14 | } 15 | 16 | // Deposit Contract 17 | 18 | // Check contract 19 | } 20 | } 21 | | 22 | 23 | // Customer Sarah creates an uses an account 24 | new sarahDeposit, sarahWithdraw, sarahCheck, ack in { 25 | openAccount!(10, *sarahDeposit, *sarahWithdraw, *sarahCheck) | 26 | sarahWithdraw!(3, *ack) | 27 | for (_ <- ack) { 28 | Nil// TODO check balance here 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /10-MoreSyntax/README.md: -------------------------------------------------------------------------------- 1 | # More Syntax 2 | 3 | By now you can already build some actual projects. And you should do it! Before we dive into the next unit, let's learn some more practical syntax so you have the real-world tools you need need to build that next killer dapp. 4 | 5 | ## Binary Operators 6 | The first new syntax will be some binary operators. Binary operators take two operands, which is why they're called _bi_ -nary. Most of these are for arithmetic. Consider these examples. 7 | 8 | [math.rho](math.rho) 9 | 10 | ### Exercise 11 | Your turn to implement the `f2c` contract. You can use the same two test cases in reverse to make sure you're getting the right result. 12 | 13 | The final binary operator you should know is `++` which is used for "concatenation" or connecting two smaller things to make a bigger thing. The operator works for lists, which we'll learn about in the next unit, as well as strings which we already know about. 14 | 15 | [greeter.rho](greeter.rho) 16 | 17 | What would the code `stdout!("I" ++ "<3" ++ "rholang")` output? 18 | - [ ] I <3 rholang 19 | - [ ] ["I", "<3", "rholang"] 20 | - [x] I<3rholang 21 | - [ ] I++<3++rholang 22 | 23 | 24 | 25 | ## Receiving Processes? 26 | 27 | We always send ____ and receive ____. 28 | - [x] processes, names 29 | - [ ] processes, processes 30 | - [ ] names, names 31 | - [ ] names, processes 32 | - [ ] no such restriction 33 | 34 | 35 | 36 | That was just a nice refresher from last unit. Hope your memory is holding up so far. If you've been writing your own rholang code, you may have found yourself really wishing you could receive processes directly so you didn't have to type all those `*`s. This is a common situation, and luckily rholang has a nice solution. We do always have to receive names, but we can bind them to name syntax like `@myValue`. Since `@myValue` is a name, `myValue` must be a process. 37 | 38 | This syntax allows us to do things like 39 | `for (@number <- someChan){double!(2 * number)}`` 40 | 41 | What code could be parred with the previous code to leave the number `24` on `double`? 42 | - [ ] @number!(12) 43 | - [x] someChan!(12) 44 | - [ ] @number!(24) 45 | - [ ] double!(48) 46 | 47 | ### Exercise 48 | Revisit the telephone game from lesson 3 and show that we could have used the `@message` pattern so `message` would be a process. 49 | 50 | What should replace the ... in `for(@x <- @y){stdout!(...)}` to make the program valid? 51 | - [ ] `@x` 52 | - [x] `x` 53 | - [ ] `*x` 54 | 55 | 56 | ## Ifs and Conditions 57 | In nearly every programming language the program's behavior can vary depending on some condition. For example I run on the trails _if_ it is nice out, but stick to the roads in _if_ it is rainy. In rholang the syntax is to do that is. 58 | 59 | ``` 60 | if ( /* condition */ ) { 61 | Nil // Do this if condition is true 62 | } 63 | else { 64 | Nil // Do this if condition is false 65 | }` 66 | ``` 67 | 68 | The situations where you will use `if` are limitless and include guessing a secret word correctly, setting the high score in a video game, determining which poker hand is higher, and calculating the winner of an election. This example contract shows how you might check the status of a bank account. 69 | 70 | [signTest.rho](signTest.rho) 71 | 72 | ### Exercise 73 | The accounting program has a problem. It says that accounts with a balance of zero are overdrawn. But really zero should be in good standing. You can fix this using the "greater than or equal" operator, `>=`. Make sure you add a few tests to make sure it works. 74 | 75 | 76 | ## Comparison Operators 77 | Now that you know how to use the `if`/`else` construct, there are lots of good comparison operators at your disposal. 78 | * `a > b` Is a greater than b? 79 | * `a < b` Is a less than b? 80 | * `a == b` Is a equal to b? 81 | * `a <= b` Is a less than _or_ equal to b? 82 | * `a >= b` Is a greater than _or_ equal to b? 83 | * `a != b` Is a unequal to b? 84 | 85 | These operators work on both numbers and text strings. Text strings are sorted lexicographically, which is a lot like alphabetically. But be careful! If you try to compare a number to a string, it will just be another stopped process. 86 | 87 | Which of these are true? 88 | - [ ] 4 < 3 89 | - [ ] "b" < "a" 90 | - [x] 5 <= 6 91 | - [ ] "hello" != "hello" 92 | 93 | ### Exercise 94 | 95 | Write a rholang program that requires the user to send in their name. In most cases the contract will simply reply with "hello", but if their name is the same as yours, it will tell them so. 96 | 97 | ## Boolean Operators 98 | Rholang also has the classic Boolean operators AND, OR, and NOT. The syntax is 99 | 100 | * `a and b` true when both `a` and `b` are true 101 | * `a or b` true when either `a` or `b` is true 102 | * `not a` true when `a` is false 103 | 104 | What would `stdout!(true and true)` output? 105 | - [x] true 106 | - [ ] false 107 | - [ ] neither; that's invalid syntax 108 | 109 | What would `stdout!(not true)` output? 110 | - [ ] true 111 | - [x] false 112 | - [ ] neither; that's invalid syntax 113 | 114 | What would `stdout!((not not true) or false)` output? 115 | - [x] true 116 | - [ ] false 117 | - [ ] neither; that's invalid syntax 118 | 119 | ### Exercise 120 | Write a contract that tells a caller whether they are eligible to vote. In order to vote you must be a certain age and of a certain country. You can pick the age and country. To use the contract, I would par in `canIVote!("Nigeria", 30)"`. 121 | 122 | ### Exercise 123 | The contract above only works for one specific country. Use what we learned about factories to enable creating many of these eligibility checkers. To create a new checker for Canada, where the voting age is 18 par in `checkerFactory!(canadaChecker, "Canada", 18)`. Then a 41-year-old Estonian would check whether he can vote in Canada with `canadaChecker!("Estonia", 41)`. Spoiler alert: He cannot vote in Canada. 124 | -------------------------------------------------------------------------------- /10-MoreSyntax/README_CN.md: -------------------------------------------------------------------------------- 1 | # 更多语法 2 | 3 | 到目前为止你已经成功写出一些实际的项目。你就应该这么做!在我们深入下一单元前,让我们学习更多实用的语法,然后你需要的现实世界的工具来创建下一代杀手级应用。 4 | 5 | ## 二元运算符 6 | 第一个学习的语法就是二元运算符。二元运算符需要有两个操作数,那是他们为什么成为“二元”的原因。大多数都是用于算术。请看下面的例子。 7 | 8 | [math.rho](math.rho) 9 | 10 | ### 练习 11 | 现在轮到你写出`f2c`的合约。你可以使用相同的两个测试案例以确保你的结果正确。 12 | 13 | 最后你应该知道的二元操作符是 `++` ,它是用于“联合”或者说把两个小东西组合成一个大东西。这个操作符适用于列表和字符串。列表我们会在下一单元学习到,字符串我们已经学习过了。 14 | 15 | [greeter.rho](greeter.rho) 16 | 17 | 代码 `stdout!("I" ++ "<3" ++ "rholang")` 会输出什么? 18 | - [ ] I <3 rholang 19 | - [ ] ["I", "<3", "rholang"] 20 | - [x] I<3rholang 21 | - [ ] I++<3++rholang 22 | 23 | 24 | 25 | ## 接收 Processes? 26 | 27 | 我们通常发送 ____ 和接收 ____. 28 | - [x] processes, names 29 | - [ ] processes, processes 30 | - [ ] names, names 31 | - [ ] names, processes 32 | - [ ] 没有严格规定 33 | 34 | 要做的事情:有一种站在门口的邮箱柜子。我们可能会把在你家门口的邮箱或者邮件槽什么的弄混。“嘿,兄弟,还是账单?我想要情书”。 35 | 36 | 那只是重温一下以前单元的内容。希望你还记住吧。如果你已经写过你自己的rholang代码,那么你可能已经发现你是多么的希望你可以直接接收"Processes"而不需要输入各种`*`。这是很普遍的一种现象,很幸运rholang有一个很好的解决方法。我们经常接收"names",当时我们可以通过`@myValue`这里来绑定"name"语法。既然`@myValue`是一个"name",那么`myValue`一定是一个"process"。 37 | 38 | 这个语法允许我们做像这样的事, 39 | `for (@number <- @"someChan"){@"double"!(2 * number)}`` 40 | 41 | 应该用什么样的代码来与前面的代码并行以达到`24`在`@"double"`中? 42 | - [ ] @number!(12) 43 | - [x] @"someChan"!(12) 44 | - [ ] @number!(24) 45 | - [ ] @"double"!(48) 46 | 47 | ### 练习 48 | 重看一下第三课中传音筒的游戏,那个展示我们已经使用了`@message`的语法模式,所以`message`是一个"process" 49 | 50 | 我们应该把 `for(@x <- @y){stdout!(...)}` 中 ... 替换为什么来让程序是正确的? 51 | - [ ] `@x` 52 | - [x] `x` 53 | - [ ] `*x` 54 | 55 | 56 | ## 条件语句 57 | 几乎在所有编程语言中,程序的行为需要根据情况来定义。例如,如果天气很好的话,我就可以跑在小道上面,但是如果下雨的话,我就在路边。rholang是这样用语法实现的。 58 | 59 | ``` 60 | if ( /* condition */ ) { 61 | Nil // Do this if condition is true 62 | } 63 | else { 64 | Nil // Do this if condition is false 65 | }` 66 | ``` 67 | 68 | 你用`if`的情况是没有限制的,包括猜一个秘密字母的正确,在游戏中设定一个高分数,决定哪张扑克牌更大和计算选举胜者。下面的例子合约展示给你看如何检查一个银行账号的状态。 69 | 70 | [signTest.rho](signTest.rho) 71 | 72 | ### 练习 73 | The accounting program has a problem. It says that accounts with a balance of zero are overdrawn. But really zero should be in good standing. You can fix this using the "greater than or equal" operator, `>=`. Make sure you add a few tests to make sure it works. 74 | 75 | 76 | ## 比较符 77 | 现在你知道了如何使用`if`/`else`,这里还有很多比较符给你使用。 78 | * `a > b` a大于b么? 79 | * `a < b` a小于b么? 80 | * `a == b` a等于b么? 81 | * `a <= b` a小于或者等于b么? 82 | * `a >= b` a大于或者等于b么? 83 | * `a != b` a不等于b么? 84 | 85 | 这些操作符可以作用于数字或者字符串。字符串按照字典顺序排序,有点像字母表排序。但是小心!如果你用一个数字与一个字符串比较,它会是另一个停止的"process"。 86 | These operators work on both numbers and text strings. Text strings are sorted lexicographically, which is a lot like alphabetically. But be careful! If you try to compare a number to a string, it will just be another stopped process. 87 | 88 | 下面哪个是对的? 89 | - [ ] 4 < 3 90 | - [ ] "b" < "a" 91 | - [x] 5 <= 6 92 | - [ ] "hello" != "hello" 93 | 94 | ### 练习 95 | 96 | 写一个rholang程序,要求用户发送他们的名字。在多数情况下,合约可以简单地回复“hello”,但是如果他们的名字与你的一样,你要告诉他们。 97 | 98 | ## 布尔操作符 99 | Rholang也有传统的布尔操作符, AND, OR, 和 NOT。语法是 100 | 101 | * 当 `a`和`b`都是真的,`a and b` 是真的 102 | * 当 `a`或`b`都是真的,`a and b` 是真的 103 | * 当 `a`是假的 ,`not a` 是真的 104 | 105 | 106 | `stdout!(true and true)` 会输出什么?? 107 | - [x] true 108 | - [ ] false 109 | - [ ] 都不是; 非法语法 110 | 111 | `stdout!(not true)` 会输出什么? 112 | - [ ] true 113 | - [x] false 114 | - [ ] 都不是; 非法语法 115 | 116 | `stdout!((not not true) or false)` 会输出什么? 117 | - [x] true 118 | - [ ] false 119 | - [ ] 都不是; 非法语法 120 | 121 | ### 练习 122 | 写一个合约告诉调用的人他们是否有资格投票。你必须达到一定的年纪和在一个规定的国家内才能投票。你可以选择年龄和国家。我可以通过并行`@"canIVote!("Nigeria", 30)"` 来使用合约。 123 | 124 | ### 练习 125 | 上面的合约指适用于一个特定的国家。用我们学过的工厂来创建出有各种资格的检查者。创建一个投票年龄为18岁的加拿大的检查者,用`@"checkerFactory"!(canadaChecker, "Canada", 18)`使用。然后用代码`canadaChecker!("Estonia", 41)`测试一个41岁的爱沙尼亚人他是否符合加拿大的投票资格。 126 | 提示:他不能在加拿大投票。 127 | -------------------------------------------------------------------------------- /10-MoreSyntax/greeter.rho: -------------------------------------------------------------------------------- 1 | new greeter in { 2 | contract greeter(name, return) = { 3 | return!("Hello there, " ++ *name) 4 | } 5 | | 6 | new stdout(`rho:io:stdout`) in { 7 | greeter!("Joshy", *stdout)| 8 | greeter!("Tom", *stdout) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /10-MoreSyntax/math.rho: -------------------------------------------------------------------------------- 1 | new c2f, f2c in { 2 | 3 | /** 4 | * Converts Celcius temperatures to Farenheit. The conversion 5 | * multiply by 9/5 and add 32 6 | */ 7 | contract c2f(celcius, return) = { 8 | return!((*celcius * 9 / 5) + 32) 9 | } 10 | | 11 | 12 | contract f2c(farenheit, return) = { 13 | Nil // TODO you complete this contract 14 | } 15 | | 16 | 17 | new stdout(`rho:io:stdout`) in { 18 | // 0 C should be 32 F 19 | c2f!(0, *stdout) 20 | | 21 | // 100 C should be 212 F 22 | c2f!(100, *stdout) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /10-MoreSyntax/signTest.rho: -------------------------------------------------------------------------------- 1 | new stdout(`rho:io:stdout`) in { 2 | for (@balance <= @"signTest") { 3 | if (balance > 0) { 4 | stdout!("Account in good standing.") 5 | } else { 6 | stdout!("Account overdrawn.") 7 | } 8 | } 9 | } 10 | | 11 | @"signTest"!(5) 12 | -------------------------------------------------------------------------------- /11-PatternMatching/README.md: -------------------------------------------------------------------------------- 1 | # Pattern Matching 2 | 3 | ## About Patterns 4 | Patterns occur all over in daily life. If you saw a new model of car that you had never seem before you would still know it is a car because it matches a mental pattern you have for cars that probably involves four wheels, two or four doors, and a windshield to see out of. 5 | 6 | Similarly, we can match sentence patterns. The sentences "I like cheese" and "I like pandas" both match the pattern "I like ____". But "I have a dog" does not match that pattern. Rholang allows programmers to use pattern matching to control program execution. That is, different code can run depending whether a process matches a certain pattern. 7 | 8 | ## The `match` construct 9 | The most obvious place that rholang uses pattern matching is in its `match` construct which works as shown here. 10 | 11 | [matching.rho](matching.rho) 12 | 13 | In this code any massage `x` that is received on the `patternMatcher` channel represents a quoted process. We compare that process (unquoted) to several patterns below and report back what pattern matches. The underscore is just a fill-in-the-blank and matches any pattern at all. It is called a "wildcard", and you'll often see it as the final pattern in a `match` construct to ensure that there is a default case if nothing else matches. 14 | 15 | 16 | 17 | Pattern matching can also be used when receiving messages with `for` or `contract`. In order for a message to be received, the message that was sent, must match the pattern that is to be received. We'll see an example of this usage shortly. 18 | 19 | ## Two cases we've seen 20 | We've already used the underscore occasionally. For example I often write `for (_ <- ack)` which means, receive a message matching _any_ pattern on the `ack` channel. It is standard practice to use the underscore when you only care that you _have_ received a message, but not _what_ message. 21 | 22 | We also used pattern matching in the previous lesson when we learned how to receive processes. When we write `for (@p <- x)` it means receive any message that matches the pattern of a quoted process, and bind that quoted process to the p. 23 | 24 | What would the variable `p` be bound to in `x!("hello") | for(@p <- x){Nil}` 25 | - [ ] `@"hello"` 26 | - [x] `"hello"` 27 | - [ ] `hello` 28 | - [ ] `4` 29 | 30 | What would the variable `p` be bound to in `x!("hello" | 4) | for(@{"hello" | p} <- x){Nil}` 31 | - [ ] `@"hello"` 32 | - [ ] `"hello"` 33 | - [ ] `hello` 34 | - [x] `4` 35 | 36 | ## Syntactic sugar 37 | ![Yummy, syntactic sugar. Now with extra curly braces.](sugar.png) 38 | It turns out that pattern matching can be used to totally replace the `if`/`else` construct we learned previously. In fact, that is exactly what `if`/`else` means under the hood. Because it is just shorthand for other syntax, `if`/`else` is said to be syntactic sugar. The following code snippets are exactly equivalent 39 | ``` 40 | if (cond) { 41 | // Do Process P 42 | } 43 | else { 44 | // Do Process Q 45 | } 46 | ``` 47 | into 48 | ``` 49 | match cond { 50 | true => // Do Process P 51 | false => // Do Process Q 52 | } 53 | ``` 54 | 55 | ### Exercise 56 | Rewrite our `signTest.rho` example from the previous lesson to use `match` instead of the sugary `if`/`else`. 57 | 58 | How could we rewrite the first `match` example above to use `if`/`else`? 59 | - [ ] Just the reverse of the previous exercise 60 | - [ ] Start with `if (x == a|b)` 61 | - [x] We can't because that example matches patterns more complex than just `true` and `false` 62 | 63 | 64 | ## A Nicer Greeter 65 | Let's make a nicer greeter that still says hello even if we don't tell it our name. The key here is that we have two different contracts listening on the exact same `greeter` channel. 66 | [greeter2.rho](greeter2.rho) 67 | 68 | You can probably understand how each of those contracts works individually. The interesting new part is how rholang decides which contract to actually run when a message comes along on the `greeter` channel. The trick is that rholang will run whichever contract has parameters that match the pattern we sent. If I send two parameters, the greeter that takes two parameters will be called. If I send just one parameter, the contract that takes just one parameter will be called. In the future, rholang will also support pattern matching on the _type_ of the parameters sent. 69 | 70 | ### Exercise 71 | Write a series of contracts that calculate the area of a rectangle. In the most obvious case the caller will provide both a length and width. But the user may also provide only a single width in which case the rectangle is actually a square and both sides are the provided width. Finally, the user may provide no dimensions at all in which case the rectangle is a 1x1 square. 72 | 73 | ## Advanced pattern matching 74 | You can do cool things with pattern matching like `for(@{x!(P)} <- y){ Q }` which will only reduce if the process sent on channel `x` matches the pattern of a single send. Then in the process Q you will have bound the variables `x`, the channel, and `P`, the process being sent 75 | 76 | [sendASend.rho](sendASend.rho) 77 | 78 | Will `x!("hello") | for ({"hello" | "world"} <- x){Nil}` cause a comm event? 79 | - [ ] Yes because the send and receive are on the same channel 80 | - [ ] Yes because the send and receive are on the same channel AND the pattern matches 81 | - [ ] No because the send and receive are on different channels 82 | - [x] No because the send and receive are on the same channel, but the pattern doesn't match 83 | 84 | ## Unions and Intersections 85 | 86 | There may be times when you want to match either of two patterns, or you want to match both a two patterns. These operations feel similar to the Booleans we discussed in the last lesson, but we use different operators when pattern matching. 87 | 88 | To match any one of several patterns you use the "union" operator, `\/` 89 | 90 | [union.rho](union.rho) 91 | 92 | To match both of two patterns you use the "intersection" operator, `/\`. In this example we are verifying that registration data is valid. A registrant must supply their name and age, and may supply any amount of additional data. By the way, this technique for storing key-value data is often known as "RHOCore". 93 | 94 | [intersection.rho](intersection.rho) 95 | 96 | Notice I called my stdout channel `print` that time. You can call those names anything you'd like. Although it's generally good to be consistent so as not to confuse anyone. From here on I'll stick with `stdout`. 97 | 98 | ### Exercise 99 | The union example here is pretty basic. Expand it so it can match more languages and more words. Also write tests that show what happens when only the default pattern is matched. 100 | 101 | The logical connectives discussed in this section have some subtle behavior related to binding that is beyond the scope of this tutorial. I encourage you to experiment with example programs, and refer to the Rholang manual when it becomes available. 102 | 103 | ## More About Bundles 104 | Several lessons ago we discussed how bundles can be used to make read- or write-only channels. But we haven't yet discussed their namesake feature. Bundles can be used to "bundle up" compound names so that they can't be taken apart by pattern matching. 105 | 106 | In this example code an army has a missile and they maintain control of launching the missile by building the capability on an unforgeable name. Because of diplomatic relationships, the army will allow the public to inspect the missile for safety, but certainly not launch it. 107 | 108 | [missileUnsafe.rho](missileUnsafe.rho) 109 | 110 | ### Exercise 111 | The army has made a terrible mistake here and anyone can launch their missile. Try to think of a way that an outside could launch this missile. 112 | 113 | Answer: 114 | [missileAttack.rho](missileAttack.rho) 115 | 116 | In order to solve the problem the army simply gives out a bundled version of the compound name so that it cannot be taken apart by pattern matching. 117 | 118 | [missileSafe.rho](missileSafe.rho) 119 | 120 | What will be output when the attack is run on the safe code? 121 | - [ ] "launching..." 122 | - [ ] "inspecting..." 123 | - [ ] "failed to launch..." 124 | - [x] nothing 125 | -------------------------------------------------------------------------------- /11-PatternMatching/README_CN.md: -------------------------------------------------------------------------------- 1 | # 模式匹配 2 | 3 | ## 关于模式 4 | 5 | 模式其实经常出现在我们的日常生活中。如果你看到一辆你从来没有见过的新型车而你仍然知道那是一辆车因为它匹配你心里对车的模式的定义,4个轮子,两个或者4个门还有挡风玻璃。 6 | 7 | 相似地,我们可以匹配句式模式。句子“我喜欢芝士”和“我喜欢熊猫”都匹配模式“我喜欢____”。但是“我有一只狗”就不匹配那样的模式。Rholang允许程序员使用模式匹配来控制程序的运行。就是说,不同的代码能根据一个“process”是否匹配一个特定的模式来执行。 8 | 9 | ## `match` 结构 10 | 11 | rholang使用模式匹配最明显的一个地方就是它的`match`结构,它的工作原理请看下面。 12 | 13 | [matching.rho](matching.rho) 14 | 15 | 在这个代码里,任何一条从`patternMatcher`通道中获取的信息`x`代表一个标记的"process"。我们拿"process"(未标记)与一些下面的模式比较一下,然后看看那些模式是匹配的。下划线仅仅是用来填空的,它可以匹配任何模式。它被称为"通配符",你可以经常看到它在`match`结构中用作最后的模式匹配以保证如果没有模式匹配的话就使用默认的情况处理。 16 | 17 | 18 | 19 | 模式匹配也可以在使用`for`或者`contract`时候使用。为了让信息成功被接收,发出去的信息必须匹配应该要被接收的模式。我们一会可以看到一个这种用途的例子。 20 | 21 | ## 我们看到的两种情况 22 | 我们有时候会使用下划线。例如我经常会使用`for (_ <- ack)`,这样代表ack通道里的信息无论匹配什么模式都接收。当你只关心你是否接收一个信息而不是接收信息的内容的时候就可以用下划线来表示,这是一种标准用法。 23 | 24 | 我们也可以在前面我们学习到如何接收“processes”的课程中的使用模式匹配。当我们写`for (@p <- x)` 时候,这代码的意思是接收所有匹配标记process模式的信息,然后把“process”绑定到p。 25 | 26 | `p`在`x!("hello") | for(@p <- x){Nil}` 中会绑定到什么样的变量 27 | - [ ] `@"hello"` 28 | - [x] `"hello"` 29 | - [ ] `hello` 30 | - [ ] `4` 31 | 32 | `p`在`x!("hello" | 4) | for(@{"hello" | p} <- x){Nil}` 中会绑定到什么样的变量 33 | - [ ] `@"hello"` 34 | - [ ] `"hello"` 35 | - [ ] `hello` 36 | - [x] `4` 37 | 38 | ## 语法糖 39 | ![Yummy, syntactic sugar. Now with extra curly braces.](sugar.png) 40 | 其实我们完全可以用模式匹配来替换到之前我们学习到的 `if`/`else`。事实上,那正是 `if`/`else` 内在实现的方式。因为那个只是其他语法的速记,所以`if`/`else`也可以说是语法糖。下面的两段代码其实作用完全一样。 41 | ``` 42 | if (cond) { 43 | // Do Process P 44 | } 45 | else { 46 | // Do Process Q 47 | } 48 | ``` 49 | into 50 | ``` 51 | match cond { 52 | true => // Do Process P 53 | false => // Do Process Q 54 | } 55 | ``` 56 | 57 | ### 练习 58 | 用`march`而不是`if`/`else`来重写我们前面课程的`signTest.rho`的例子 59 | 60 | 我们应该如何用`if`/`else`重写上面第一个`match`的例子? 61 | - [ ] 仅仅只是反转前面的练习 62 | - [ ] 以`if (x == a|b)`开始 63 | - [x] 我们无法重写因为上面的例子比只是`true`和`false`更复杂 64 | 65 | 66 | ## 一个更友好的招待员 67 | 让我们制作一个更友好的招待员,这个招待员即使我们不告诉他我们的名字,他也会说你好。关键部分在于我们有两个不一样的合约在监听同一个`greeter`通道。 68 | [greeter2.rho](greeter2.rho) 69 | 70 | 你可能可以明白每个合约单独是如何运行的。有意思的部分是如何让rholang决定当信息从`greeter`通道过来的时候实际上哪一个合约去执行。方法在于rholang应该根据哪一个合约的参数匹配我们发送的模式。如果我发送两个参数,招待员就使用两个参数来调用。如果我只发送一个参数,那么合约就应该使用一个参数来调用。在未来,rholang将会支持发送参数的类型做模式匹配。 71 | 72 | ### 练习 73 | 写一系列的合约来计算长方形的面积。在大多数明显的情况下,调用的人需要提供长度和宽度。但是用户可能也只提供单个宽度,这种情况通常长方形实际上是一个正方形,长宽都是提供的的宽度长度。最后,用户也可能什么都不提供,这种情况就是长方形是1x1的正方形。 74 | 75 | ## 高级模式匹配 76 | 你可以通过模式匹配做一些有意思的事情,比如`for(@{x!(P)} <- y){ Q }`只会在"process"在频道`x`发送匹配单独发送模式的时候才会计算。然后在process Q 里面你将会绑定变量 `x`这个频道和 `p`这个被发送的process。 77 | 78 | [sendASend.rho](sendASend.rho) 79 | 80 | `x!("hello") | for ({P | Q} <- x){Nil}` 会产生一个通信事件么? 81 | - [ ] 会的,因为发送和接收在同一个通道 82 | - [ ] 会的,因为发送和接收在同一个通道并且模式匹配 83 | - [ ] 不会的,因为发送和接收在不同一个通道 84 | - [x] 不会的,因为发送和接收在同一个通道但是模式不匹配。 85 | 86 | ## Unions and Intersections 87 | 88 | 可能有时候你想要匹配两种模式中的一种或者同时匹配两种模式。这些操作都与我们使用上一节课讨论的布尔运算相似,但是我们当我们要模式匹配时要使用不同的运算符。 89 | 90 | 你可以用"unions"操作符,`\/`来匹配其中一种模式。 91 | 92 | [union.rho](union.rho) 93 | 94 | 使用"intersection"操作符来同时匹配两个模式。在这个例子里,我们检查注册数据是否有效。一个注册者必须提供他们的名字和年龄,可能需要提供一些额外的数据。顺便说一句,这项保存键值得技术经常也成为"RHOCore"。 95 | To match both of two patterns you use the "intersection" operator, `/\`. In this example we are verifying that registration data is valid. A registrant must supply their name and age, and may supply any amount of additional data. By the way, this technique for storing key-value data is often known as "RHOCore". 96 | 97 | [intersection.rho](intersection.rho) 98 | 99 | ### 练习 100 | 这个union语法的例子是相当基础的。扩展那个代码使它可以匹配更多的语言和更多的单词。同时也写出测试来展示当只有默认模式被匹配时候会发生什么。 101 | 102 | 在这一节当中讨论的逻辑连接与绑定有一点关系,但是那超出本教程的范围。我鼓励你通过例子程序来做式样,当你可以的时候可以参考rholang使用手册。 103 | 104 | ## 更多关于Bundles 105 | 几节课前,我们讨论了怎么使用bundles来创建可读或者可写的通道。但是我们还没有讨论过他们的同名特征。Bundles可以用来绑定组合的名字,让他们在做模式匹配的时候无法分开。 106 | 107 | 在这个例子中,一个军队有一个导弹,他们通过创建在一个不可伪造的"name"上创建功能来保持对导弹的控制。由于外交关系,军队需要允许公众检查导弹的安全,但是不能发射它。 108 | 109 | [missileUnsafe.rho](missileUnsafe.rho) 110 | 111 | ### 练习 112 | 军队在这里犯了一个很严重的错误,所有人都可以发射他们的导弹。请想一个让外界发射导弹的方法。 113 | 114 | 答案: 115 | [missileAttack.rho](missileAttack.rho) 116 | 117 | 为了解决这个问题,军队只要简单地给出一个bundled版本的组合"name",让他们无法再模式匹配中分开。 118 | 119 | [missileSafe.rho](missileSafe.rho) 120 | 121 | 当攻击在安全的代码上运行时,会有什么输出? 122 | - [ ] "launching..." 123 | - [ ] "inspecting..." 124 | - [ ] "failed to launch..." 125 | - [x] 什么都没有 126 | -------------------------------------------------------------------------------- /11-PatternMatching/greeter2.rho: -------------------------------------------------------------------------------- 1 | 2 | new greeter in { 3 | contract greeter(name, return) = { 4 | return!("Hello there, " ++ *name) 5 | } 6 | | 7 | // Default case where there is no name 8 | contract greeter(return) = { 9 | return!("Hello there, world") 10 | } 11 | | 12 | new stdout(`rho:io:stdout`) in { 13 | greeter!("Joshy", *stdout)| 14 | greeter!("Tom", *stdout) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /11-PatternMatching/intersection.rho: -------------------------------------------------------------------------------- 1 | new print(`rho:io:stdout`), register in { 2 | 3 | for (@{{@"name"!(_) | _} /\ {@"age"!(_) | _}} <= register){ 4 | print!("Both name and age were in the data") 5 | } 6 | | 7 | 8 | register!(@"name"!(Nil)) 9 | | 10 | register!(@"age"!(Nil)) 11 | | 12 | register!(@"name"!(Nil) | @"age"!(Nil)) 13 | | 14 | register!(@"name"!(Nil) | @"age"!(Nil) | @"height"!(175)) 15 | } 16 | -------------------------------------------------------------------------------- /11-PatternMatching/lookingForMessagesPatternMatching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/11-PatternMatching/lookingForMessagesPatternMatching.png -------------------------------------------------------------------------------- /11-PatternMatching/matching.rho: -------------------------------------------------------------------------------- 1 | new patternMatcher, stdout(`rho:io:stdout`) in { 2 | 3 | for (x <= patternMatcher) { 4 | match *x { 5 | Nil => stdout!("Got the stopped process") 6 | "hello" => stdout!("Got the string hello") 7 | [x, y] => stdout!("Got a two-element list") 8 | Int => stdout!("Got an integer") 9 | _ => stdout!("Got something else") 10 | } 11 | } 12 | | 13 | 14 | // Make sure the pattern matcher works 15 | patternMatcher!({for(@0 <- @0){0}}) 16 | | 17 | patternMatcher!({@"world"!("hello")}) 18 | | 19 | patternMatcher!({0|"hello"}) 20 | | 21 | patternMatcher!(Nil) 22 | } 23 | -------------------------------------------------------------------------------- /11-PatternMatching/missileAttack.rho: -------------------------------------------------------------------------------- 1 | new getInspectionChannel, ack in { 2 | getInspectionChannel!(*ack)| 3 | for(@(missile, "inspect") <- ack){ 4 | @(missile, "launch")!(Nil) 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /11-PatternMatching/missileSafe.rho: -------------------------------------------------------------------------------- 1 | new getInspectionChannel, log(`rho:io:stdout`), missile in { 2 | 3 | contract @(*missile, "launch")(_) = { 4 | log!("launching...") 5 | } 6 | | 7 | contract @(*missile, "inspect")(_) = { 8 | log!("inspecting...") 9 | } 10 | | 11 | 12 | contract getInspectionChannel(return) = { 13 | return!(bundle+{(*missile, "inspect")}) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /11-PatternMatching/missileUnsafe.rho: -------------------------------------------------------------------------------- 1 | new log(`rho:io:stdout`), missile in { 2 | 3 | contract @(*missile, "launch")(_) = { 4 | log!("launching...") 5 | } 6 | | 7 | contract @(*missile, "inspect")(_) = { 8 | log!("inspecting...") 9 | } 10 | | 11 | 12 | contract @"getInspectionChannel"(return) = { 13 | return!((*missile, "inspect")) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /11-PatternMatching/sendASend.rho: -------------------------------------------------------------------------------- 1 | new patternMatcher, stdout(`rho:io:stdout`) in { 2 | 3 | for (x <= patternMatcher) { 4 | match *x { 5 | Nil => stdout!("Got the stopped process") 6 | {_!(_)} => stdout!("Got a send") 7 | {for(@0 <- _){_}} => stdout!("Got a receive on @0") 8 | _ => stdout!("Got something else") 9 | } 10 | } 11 | | 12 | 13 | // Make sure the pattern matcher works 14 | patternMatcher!({for(@0 <- @0){0}}) 15 | | 16 | patternMatcher!({@"world"!("hello")}) 17 | | 18 | patternMatcher!({0|"hello"}) 19 | | 20 | patternMatcher!(Nil) 21 | } 22 | -------------------------------------------------------------------------------- /11-PatternMatching/sugar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/11-PatternMatching/sugar.png -------------------------------------------------------------------------------- /11-PatternMatching/union.rho: -------------------------------------------------------------------------------- 1 | new log(`rho:io:stdout`), binderChecker in { 2 | contract binderChecker(@data, return) = { 3 | match data { 4 | "nombre" \/ "name" => return!("name-like") 5 | _ => return!("not name-like") 6 | } 7 | } 8 | | 9 | binderChecker!("name", *log) 10 | | 11 | binderChecker!("nombre", *log) 12 | } 13 | -------------------------------------------------------------------------------- /12-DataStructures/README.md: -------------------------------------------------------------------------------- 1 | # Data Structures 2 | 3 | It is common for programs to process and store real world data. And whenever you have lots of data it is important to keep it organized so you can find the information you need quickly. In the analog world, paper files are kept organized by stacking them, putting them in folders, and file cabinets. The same concept applies in programming, and rholang is no exception (for once!). 4 | 5 | If you've never seen data structures before, you will likely want to consult some other references, and look at additional example code. 6 | 7 | ## String Methods 8 | Let's start with a familiar idea. We've seen strings since the very first program in lesson one. Really strings are just a nice way to organize a bunch of characters, and that makes them a data structure. Like all data structures, strings have "methods" that you can perform on them. 9 | 10 | String's length method tells how many characters are in a string. While it's slice method creates a new string with some characters sliced off of each end. Strings also support the `++` operator for concatenation. 11 | [wordLength.rho](wordLength.rho) 12 | 13 | What is the result of `"hello world".length()`? 14 | - [ ] 2 15 | - [ ] 10 16 | - [x] 11 17 | - [ ] undefined 18 | - [ ] "hello" 19 | 20 | Which of the following evaluates to "ello"? 21 | - [x] `"hello world".slice(1, 5)` 22 | - [ ] `"hello world".slice(0, 5)` 23 | - [ ] `"hello world".slice(1, 4)` 24 | - [ ] `"hello world".slice(3, 6)` 25 | 26 | Strings also have a method called `hexToBytes` that is designed to work on strings that contain valid hexadecimal numbers. It gives back a byte array that is represented by that hex number. Try to run `"1241243e".hexToBytes()` 27 | 28 | 29 | Pro tip: It is also possible to slice a byte array. Experiment with that on your own. 30 | 31 | 32 | 33 | ## Tuples 34 | Tuple can rhyme with either "couple" or "drupal"; both pronunciations are correct. You've seen tuples before when you wrote contracts that take in multiple arguments like `contract c(x, y, z) = { Nil }`. The number of items in a tuple is know as its arity. So the tuple received by contract `c` is arity three. 35 | 36 | Tuples contain several pieces of data **in order**. They are always a fixed arity, and have relatively few methods. Thus they are the least interesting data structure, but at the same time, the most fundamental. Let's look at some of the methods offered by tuples. 37 | 38 | [tuple.rho](tuple.rho) 39 | 40 | What is the arity of [3, 4, 9, Nil]? 41 | - [ ] 3 42 | - [x] 4 43 | - [ ] 9 44 | - [ ] Nil 45 | 46 | What would `("a", "b", "c").nth(3)` evaluate to? 47 | - [ ] 3 48 | - [x] That's an error 49 | - [ ] "c" 50 | - [ ] ("a", "b", "c") 51 | 52 | ### Exercise 53 | Write a program that takes in a 4-tuple and prints elements 0 and 3 to the screen. 54 | 55 | 56 | ## Lists 57 | Lists are a lot like tuples, but they are made with square brackets instead of parentheses. They also have more methods, and can be concatenated or glued together using the `++` operator just like strings can. Here are examples of all of list's methods. 58 | 59 | [list.rho](list.rho) 60 | 61 | ### Exercise 62 | Implement the body of the following running log contract. The user will call the contract every time they go for a run passing in the distance that they ran. The contract will keep track of all the runs in a list. You may also write methods to get all the run data, or get the total distance the user has run. 63 | 64 | ```rholang 65 | new logRun, runsCh in { 66 | 67 | // No runs to start with 68 | runsCh!([])| 69 | 70 | contract logRun(distance) = { 71 | // Your code here 72 | } 73 | } 74 | ``` 75 | 76 | ## Sets 77 | 78 | Sets are similar to lists in some ways, but the one big difference is that sets **are not ordered**. A set is a collection of processes, but there is no first or last item in the set. There are also **no duplicates** allowed in sets. Let's take a look at some of set's methods. 79 | 80 | [set.rho](set.rho) 81 | 82 | Which code would produce a set of all club members who have not paid their dues? 83 | - [x] `allMembers.diff(paidMembers)` 84 | - [ ] `paidMembers.diff(allMembers)` 85 | - [ ] `paidMembers.union(allMembers)` 86 | - [ ] `paidMembers.contains(allMembers)` 87 | 88 | What is the result of `Set(1,2,3) == Set(3,2,1)` 89 | - [x] `true` 90 | - [ ] `false` 91 | - [ ] invalid syntax 92 | - [ ] `Set(2)` 93 | 94 | ## Maps 95 | Maps are a lot like sets but they contain **key value pairs**. Maps are also unordered, but when you add an item (which is now known as a key) you also add an associated value. Here are examples of all of map's methods. 96 | 97 | [map.rho](map.rho) 98 | 99 | What is the result of `{"years": 1, "weeks": 52, "days": 365}.get(52)` 100 | - [ ] weeks 101 | - [ ] years 102 | - [ ] 52 103 | - [x] Nil 104 | 105 | To demonstrate the usefulness of maps in rholang, let's consider this contract that looks up the capital of any country (that I bothered to type). 106 | 107 | [capitalOf.rho](capitalOf.rho) 108 | 109 | ## Exercise 110 | Starting from the example code above, make a Countries and Capitals quiz game where the user calls up a contract and get's back a challenge country as well as an answer channel. The user then sends her best guess for that country's capital back over the answer channel and gets back a boolean for whether she was correct. 111 | 112 | To learn how to use this game interactively with a nice user interface, check out some dapp development examples such as the [nth caller game](https://github.com/JoshOrndorff/nth-caller-game) 113 | 114 | ## Exercise 115 | Map's `diff` method takes another map as an argument. What happens if the diff map has some of the same keys but with different values associated. For example: 116 | ``` 117 | {"a": "A", "b": "B", "c": "C"}.diff({"a": 25}) 118 | ``` 119 | 120 | 121 | ## Method Summary Table 122 | 123 | That was a lot of info about data structures in one go. So here is a handy table to remind you what methods exist. This info is also on the [cheat sheet](../cheatSheet). 124 | 125 | Method | Tuple | List | Map | Set 126 | --- | ----- | ----- | ----- | ----- 127 | nth | x | x | | 128 | toByteArray | x | x | x | x 129 | union | | | x | x 130 | diff | | | x | x 131 | add | | | | x 132 | delete | | | x | x 133 | contains | | | x | x 134 | get | | | x | 135 | getOrElse | | | x | 136 | set | | | x | 137 | keys | | | x | 138 | size | | | x | x 139 | length | | x | | 140 | slice | | x | | 141 | 142 | ## Sending and Receiving on Compound Names 143 | We've learned about several interesting data structures in this lesson. Data structures are processes just like integers, booleans, and `Nil`. So they can be quoted and turned into names like all those other processes. We can build contracts on those names just like we can any other names. Names that are built on data structures such as tuples are often called compound names. 144 | 145 | In this example, Alice and Bob each have one unforgeable name (that I've called key). The keys may be useful on their own (for things not shown in the snippet), but only when used together, can the contract shown be called. This is known as "rights amplification". 146 | ``` 147 | new alice, bob, key1, key2, stdout(`rho:io:stdout`) in { 148 | 149 | alice!(*key1)| 150 | bob!(*key2)| 151 | 152 | contract @(*key1, *key2)(_) = { 153 | stdout!("Congratulations, Alice and Bob, you've cooperated.") 154 | } 155 | } 156 | ``` 157 | 158 | 159 | 160 | What tuple is used to build the compound name in `contract @(*self, "getVal")(_) = { Nil }`? 161 | - [ ] `self` 162 | - [ ] `"getval"` 163 | - [x] `(*self, "getVal")` 164 | - [ ] `@(*self, "getVal")` 165 | - [ ] `@"getVal"` 166 | -------------------------------------------------------------------------------- /12-DataStructures/capitalOf.rho: -------------------------------------------------------------------------------- 1 | new capitalOf, print(`rho:io:stdout`) in { 2 | new mapCh in { 3 | 4 | // Use a persistent send instead of peeking later 5 | mapCh!!({"Canada": "Ottawa", 6 | "Nigeria": "Abuja", 7 | "Germany": "Berlin", 8 | "Antarctica": Nil, 9 | "China": "Beijing", 10 | "Ecuador": "Quito", 11 | "Australia": "Canberra"}) 12 | | 13 | contract capitalOf(@country, return) = { 14 | for (@map <- mapCh) { 15 | return!(map.getOrElse(country, "I don't know")) 16 | } 17 | } 18 | } 19 | | 20 | new answerCh in { 21 | capitalOf!("Canada", *answerCh)| 22 | for (@cap <- answerCh) { 23 | print!("Capital of ${cntry} is ${cap}." %% {"cntry": "Canada", "cap": cap}) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /12-DataStructures/list.rho: -------------------------------------------------------------------------------- 1 | new lCh, stdout(`rho:io:stdout`) in { 2 | 3 | // Make a new list, l 4 | lCh!!([3, 4, 5])| 5 | 6 | // Test nth 7 | for (@l <- lCh){ 8 | stdout!("Test nth. Expected: 5. Got: ${ans}" %% {"ans": l.nth(2)}) 9 | } 10 | | 11 | 12 | // Test toByteArray 13 | for (@l <- lCh){ 14 | stdout!(["Test toByteArray. Got: ", l.toByteArray()]) 15 | } 16 | | 17 | 18 | // Test slice 19 | for (@l <- lCh){ 20 | stdout!(["Test slice. Expected: [4, 5]. Got: ", l.slice(1, 3)]) 21 | } 22 | | 23 | 24 | // Test length 25 | for (@l <- lCh){ 26 | stdout!("Test length. Expected: 3. Got: '${ans}" %% {"ans": l.length()}) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /12-DataStructures/map.rho: -------------------------------------------------------------------------------- 1 | new mCh, print(`rho:io:stdout`) in { 2 | 3 | mCh!!({"a": 3, "b": 4, "c": 5})| 4 | 5 | // Test toByteArray 6 | for (@m <- mCh){ 7 | print!(["Test toByteArray. Got: ", m.toByteArray()]) 8 | } 9 | | 10 | 11 | // Test Union 12 | for (@m <- mCh){ 13 | print!(["Test union. Expected: {a: 3, b: 4, c: 5, d: 6}. Got: ", m.union({"d": 6})]) 14 | } 15 | | 16 | 17 | // Test Diff 18 | for (@m <- mCh){ 19 | print!(["Test diff. Expected: {b: 4, c: 5}. Got: ", m.diff({"a": 3})]) 20 | } 21 | | 22 | 23 | // Test Delete 24 | for (@m <- mCh){ 25 | print!(["Test delete. Expected: {a: 3, b: 4}. Got: ", m.delete("c")]) 26 | } 27 | | 28 | 29 | // Test Contains 30 | for (@m <- mCh){ 31 | print!(["Test contains. Expected: true. Got: ", m.contains("c")])| 32 | print!(["Test contains. Expected: false. Got: ", m.contains("d")]) 33 | } 34 | | 35 | 36 | // Test Get 37 | for (@m <- mCh){ 38 | print!(["Test get. Expected: 4. Got: ", m.get("b")]) 39 | } 40 | | 41 | 42 | // Test GetOrElse 43 | for (@m <- mCh){ 44 | print!(["getOrElseSuccessful. Expected: 4. Got: ", m.getOrElse("b", "?")])| 45 | print!(["getOrElseFailed. Expected: ?. Got: ", m.getOrElse("d", "?")]) 46 | } 47 | | 48 | 49 | // Test Set 50 | for (@m <- mCh){ 51 | print!(["Test set. Expected {a: 3, b: 2, c: 5}. Got: ", m.set("b", 2)]) 52 | } 53 | | 54 | 55 | // Test Keys 56 | for (@m <- mCh){ 57 | print!(["Test keys. Expected Set(a, b, c)). Got: ", m.keys()]) 58 | } 59 | | 60 | 61 | // Test Size 62 | for (@m <- mCh){ 63 | print!(["Test size. Expected 3. Got: ", m.size()]) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /12-DataStructures/set.rho: -------------------------------------------------------------------------------- 1 | new sCh, stdout(`rho:io:stdout`) in { 2 | 3 | sCh!!(Set(3, 4, 5))| 4 | 5 | // Test toByteArray 6 | for (@s <- sCh){ 7 | stdout!(["Test toByteArray. Got: ", s.toByteArray()]) 8 | } 9 | | 10 | 11 | // Test Add 12 | for (@s <- sCh){ 13 | stdout!(["Test add. Expected Set(3, 4, 5, 6), Got: ", s.add(6)]) 14 | } 15 | | 16 | 17 | // Test Diff 18 | for (@s <- sCh){ 19 | stdout!(["Test diff. Expected: Set(5) Got: ", s.diff(Set(3, 4))]) 20 | } 21 | | 22 | 23 | // Test Union 24 | for (@s <- sCh){ 25 | stdout!(["Test union. Expected: Set(1, 2, 3, 4, 5). Got: ", s.union(Set(1, 2))]) 26 | } 27 | | 28 | 29 | // Test Delete 30 | for (@s <- sCh){ 31 | stdout!(["Test delete. Expected: Set(3, 4). Got: ", s.delete(5)]) 32 | } 33 | | 34 | 35 | // Test Contains 36 | for (@s <- sCh){ 37 | stdout!(["Test contains. Expected: true. Got:", s.contains(5)])| 38 | stdout!(["Test contains. Expected: false. Got: ", s.contains(6)]) 39 | } 40 | | 41 | 42 | // Test Size 43 | for (@s <- sCh){ 44 | stdout!("Test size. Expected 3. Got: ${ans}" %% {"ans": s.size()}) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /12-DataStructures/tuple.rho: -------------------------------------------------------------------------------- 1 | new tCh, print(`rho:io:stdout`) in { 2 | 3 | tCh!!((3, 4, 5))| 4 | 5 | // Test nth 6 | for (@t <- tCh){ 7 | print!(["Test nth. Expected: 5. Got ", t.nth(2)]) 8 | } 9 | | 10 | 11 | // Test toByteArray 12 | for (@t <- tCh){ 13 | print!(["toByteArray test. Got: ", t.toByteArray()]) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /12-DataStructures/wordLength.rho: -------------------------------------------------------------------------------- 1 | new wordLength, stdout(`rho:io:stdout`) in { 2 | contract wordLength(@word) = { 3 | stdout!("How many characters in " ++ word)| 4 | stdout!(word.length())| 5 | stdout!("Shorter version: " ++ word.slice(0, 5)) 6 | } 7 | | 8 | wordLength!("Cantaloupe") 9 | } 10 | -------------------------------------------------------------------------------- /13-Iteration/README.md: -------------------------------------------------------------------------------- 1 | # Iteration and Recursion 2 | Let's start with some exercises to review old topics and motivate the problem we're solving in this lesson. 3 | 4 | 5 | ### Exercise 6 | Write a program that prints a countdown of the numbers 3, 2, 1 in order on the screen. 7 | 8 | ### Exercise 9 | Now countdown from 5. 10 | 11 | ### Exercise 12 | Write a contract that returns a random number between 1 and 3. 13 | Hint, you can use race conditions to your advantage here. 14 | 15 | ### Exercise 16 | Now make it choose a random number between 1 and 10. 17 | 18 | Is this method of writing a random number generator sustainable? 19 | - [ ] Yes 20 | - [x] No 21 | 22 | 23 | 24 | ## Iteration 25 | TODO Julie drawing for iteration. 26 | 27 | 28 | Iterating is the process of ..... Many programming languages use iteration as a fundamental way of controlling the flow of their programs. Iteration inherently means doing a process to one item then the next then the next. Because rholang is a fully concurrent programming language this is impossible. But that's actually a strength! 29 | 30 | ``` 31 | manually iterate through the list [1, 2, 3, 4] 32 | ``` 33 | 34 | This process is clearly not sustainable because long lists would be extremely deeply nested. Worse, any code that we actually write would have a maximum depth. And we don't want to limit the length of our list. Consider this crafty code 35 | 36 | ``` 37 | Simple recursion that passes a counter and compares it to the lists length 38 | ``` 39 | 40 | ``` 41 | Better version that uses pattern matching to detect empty list 42 | ``` 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ## Recursion 52 | Todo Julie drawing about recursion or a picture of a picture or something. 53 | 54 | map 55 | filter 56 | sumlist 57 | 58 | 59 | ## heading 60 | 61 | ### Exercise 62 | Write a contract that takes in two integers that represent a minimum and a maximum. 63 | 64 | Exercise: group forwarder. I, the king, send messages to the forwarder who copies them to all the recipients. Rather than just having kill switch, I have the ability to change group subscription. 65 | 66 | 67 | 68 | Idea: [head ... tail] 69 | -------------------------------------------------------------------------------- /14-PlayingGames/README.md: -------------------------------------------------------------------------------- 1 | # Games 2 | 3 | Smart contracts have a lot in common with games. They have clearly defined rules, and outcomes. Once players agree to join a game they have a specific set of moves they can make. A few of the examples we've seen already are clearly games, such as the patience game. Others are not so obviously games, but even they can be modeled as games. For example the click counter was a game where players could go in any order and the two kinds of moves they could make were increment and reset. Some games, like patience, have final results while others, like counter, continue forever. 4 | 5 | Because so many real-world interactions can be modeled as games, we will take a look at a few more here. After this unit, the tutorial continues primarily as example programs with exercises commented in. The majority of those exercises are games of one variety or another. 6 | 7 | ## Coordination game 8 | 9 | ## High Card 10 | 11 | ## Randomness 12 | 13 | randomFromRange 14 | 15 | 16 | 17 | Although this technique for generating randomness will often work in practice remembe that in a blockchain context the "random" result is entirely up to the network validators. If the validators have a stake in your game, they can influence the result from outside the obvious rules of the game. How to get true randomness into blockchains is an open question. 18 | 19 | 20 | 21 | ## Rock Paper Scissors 22 | This is a big exercise? 23 | 24 | ## More to look forward to 25 | * tic tac toe 26 | -------------------------------------------------------------------------------- /14-PlayingGames/Screenshot-RPS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/14-PlayingGames/Screenshot-RPS.png -------------------------------------------------------------------------------- /15-GoingOffChain/README.md: -------------------------------------------------------------------------------- 1 | # Going Off Chain 2 | 3 | So far all of our exercises have existed entirely inside the world of rholang. While rholang is meant to be a general-purpose programming language, it's current role is as a blockchain language. Many wonderful smart contracts are being written in rholang . But people don't live their whole lives on-chain. They also go outside and ply, eat dinner, and go to concerts. And while they're away doing those real-world things, they need a place to store their unforgeable names. Because unforgeable names can only exist on the blockchain. 4 | 5 | 6 | 7 | 8 | 9 | ## Name Registry 10 | The name registry provides a partial solution to the problem. To register a name follow this example. 11 | [insertArbitrary.rho](insertArbitrary.rho) 12 | 13 | 14 | To look a name up to use it later, try this 15 | [lookup.rho](lookup.rho) 16 | 17 | There is also a feature called `insertSigned` which allows contract publishers to later update their contracts, but I have security concerns about it, so I won't document it here. 18 | 19 | ## Cryptography 20 | The name registry got us close to what we need. The remaining challenge is that now that names can be made publicly accessible, how do we ensure that only authorized personnel have access to sensative contracts? Cryptography to the rescue! 21 | 22 | 23 | 24 | TODO This section is incomplete 25 | 26 | Rholang has primitives for hashing and signature verification 27 | 28 | Show how to do a simple signature verified contract on a public name 29 | Link to RSign and RChain-API 30 | -------------------------------------------------------------------------------- /15-GoingOffChain/insertArbitrary.rho: -------------------------------------------------------------------------------- 1 | new doubler, 2 | uriChan, 3 | insertArbitrary(`rho:registry:insertArbitrary`), 4 | stdout(`rho:io:stdout`) in { 5 | 6 | // This is a silly contract that we'll register 7 | contract doubler(@n /\ Int, return) = { 8 | return!(2 * n) 9 | } | 10 | 11 | // Tell the registry that we want to register 12 | // give URI back on uriChan 13 | insertArbitrary!(bundle+{*doubler} , *uriChan) | 14 | 15 | // Wait for URI response 16 | for(@uri <- uriChan) { 17 | stdout!(uri) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /15-GoingOffChain/lookup.rho: -------------------------------------------------------------------------------- 1 | new doublerCh, 2 | lookup(`rho:registry:lookup`), 3 | stdout(`rho:io:stdout`) in { 4 | 5 | // Ask the registry to lookup the URI and send the contract back on doublerCh 6 | lookup!(`rho:id:fos1m8yaki3s8g1ytzkr6boucnhab6nafoco8ww63xqj5k8aa1xfza`, *doublerCh) | 7 | 8 | // Wait to receive the answer back from the registry 9 | for( doubler <- doublerCh) { 10 | 11 | // Double a number and send the answer to stdout 12 | doubler!(7, *stdout) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Rholang By Example 2 | 3 | Learn rholang by example and experimentation. The examples and exercises are meant to be run, read, modified and completed. For best results, change anything and everything you are curious about. This tutorial is a tour of the most common and important features of rholang and a fast starting point for motivated learners. 4 | 5 | [中文教程](README_CN.md) [версия на русском](README_RU.md) 6 | 7 | ## Table of Contents 8 | * [Rholang Cheat Sheet](cheatSheet/) 9 | * [lesson 0 -- Developer Environment](00-DeveloperEnvironment/) 10 | 11 | ### Unit 1 12 | 13 | * [lesson 1 -- Sending and Standard Out](01-SendingAndStandardOut/) 14 | * [lesson 2 -- Receiving](02-Receiving/) 15 | * [lesson 3 -- Telephone, Names, and Processes](03-TelephoneNamesAndProcesses/) 16 | * [lesson 4 -- Persistent Send and Peek](04-PersistentSendAndPeek/) 17 | * [lesson 5 -- The Join Operator](05-JoinOperator/) 18 | 19 | ### Unit 2 20 | * [lesson 6 -- Unforgeable Names and Acks](06-UnforgeableNamesAndAcks/) 21 | * [lesson 7 -- Bundles and Interpolation](07-BundlesAndInterpolation/) 22 | * [lesson 8 -- State Channels And Methods](08-StateChannelsAndMethods/) 23 | * [lesson 9 -- Object Capabilities](09-ObjectCapabilities/) 24 | * [lesson 10 -- More Syntax](10-MoreSyntax/) 25 | 26 | ### Unit 3 27 | * [lesson 11 --Pattern Matching](11-PatternMatching/) 28 | * [lesson 12 -- Data Structures](12-DataStructures/) 29 | * [lesson 13 -- Iteration](13-Iteration/) (incomplete) 30 | * lesson 14 (not yet begun) 31 | * [lesson 15 -- Going Off Chain](15-GoingOffChain/) (incomplete) 32 | 33 | 34 | ## Target Audience 35 | This tutorial aims to be novice-friendly and introduce rholang from the ground 36 | up. If you've never ever programmed before, you may struggle at times, but 37 | if you know how to write a little python or javascript, you've got all the 38 | background I've assumed. 39 | 40 | You don't need to be familiar with process calculi, be a master of any other languages, or understand the underlying math. 41 | 42 | 43 | ## Additional Resources 44 | * [The Core team's tutorial](https://github.com/rchain/rchain/blob/master/docs/rholang/rholangtut.md) 45 | * Contact me through [my website](https://joshyorndorff.com/contact). 46 | 47 | ## Author and License 48 | Written by Joshy Orndorff. 49 | 50 | Illustrations by Julianne Coxe. 51 | 52 | Released under the Apache 2.0 license. 53 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # 通过示例学习rholang 2 | 3 | 通过例子和实践来学习rho语言。下面的例子和练习都很值得去运行、阅读、修改和完善。修改练习和教程中任何你感到有意思的代码,这样能够获得最好的学习效果。该教程包含了rho语言最常见以及最重要的特性,足以让开发者快速入门。 4 | 5 | ## 目录 6 | * [Rholang备忘录](cheatSheet)(未翻译) 7 | * [课程0 -- 开发环境](00-DeveloperEnvironment/README_CN.md) 8 | 9 | ### 单元 1 10 | 11 | * [课程1 -- 发送与标准输出(stdout)](01-SendingAndStandardOut/README_CN.md) 12 | * [课程2 -- 接收](02-Receiving/README_CN.md) 13 | * [课程3 -- 传音筒、"name"和“process”](03-TelephoneNamesAndProcesses/README_CN.md) 14 | * [课程4 -- 持续发送与窥探](04-PersistentSendAndPeek/README_CN.md) 15 | * [课程5 -- Join操作](05-JoinOperator/README_CN.md) 16 | 17 | ### 单元 2 18 | * [课程6 -- 不可伪造的Names和Acks](06-UnforgeableNamesAndAcks/README_CN.md) 19 | * [课程7 -- Bundles](07-Bundles/README_CN.md) 20 | * [课程8 -- 状态通道和方法](08-StateChannelsAndMethods/README_CN.md) 21 | * [课程9 -- 对象功能](09-ObjectCapabilities/README_CN.md) 22 | * [课程10 -- 更多语法](10-MoreSyntax/README_CN.md) 23 | 24 | ### 单元 3 25 | * [课程11 -- 模式匹配](11-PatternMatching/README_CN.md) 26 | 27 | ### 还在准备中的课程 28 | * [课程12 -- 数据结构](12-DataStructures/)(未翻译) 29 | * [课程13 -- 迭代](13-Iteration/)(未翻译) 30 | 31 | ## 目标人群 32 | 这个教程适用于新手,指导他们从头开始学习rholang。 33 | 如果你以前从来没有编程过,你可能有时候会遇到困难。 34 | 但是如果你以前写过Python和Javascript,那么你应该已经具备应有的背景。 35 | 36 | 我不期望你能了解process calculi,熟悉掌握其它的语言或者理解RChain社区里面讨论的所有数学理论。 37 | 38 | 39 | ## 其它资源 40 | * [Mike Stay的Rholang教程](https://developer.rchain.coop/tutorial/) 41 | * [核心团队的教程](https://github.com/rchain/rchain/blob/master/docs/rholang/rholangtut.md) 42 | * 通过[我的网站](https://joshyorndorff.com/contact)联系我 43 | 44 | ## 作者和许可证 45 | 在RChain合作社支持下,主要由Joshy Orndorff撰写,Julianne Coxe的插图。 46 | 47 | 中文版由Will和yyh1102翻译。 48 | 49 | 在Apache 2.0 证书下发布。 50 | -------------------------------------------------------------------------------- /README_RU.md: -------------------------------------------------------------------------------- 1 | # Ро на примерах 2 | Учебник языка "ро" для программистов любого уровня с примерами 3 | Мы научимся языку программирования "Ро" на примерах и будем с ним экспериментировать. Примеры и упражнения являются рабочими и подхотят для прорабатывания. Попробуйте поменять какую-либо часть кода и посмотрите, что будет происходить. Данный туториал делает обзор самых важных особенностей языка ро и может послужить хорошей отправной точкой для целеустремленного читателя. 4 | 5 | ## Содержание 6 | * [Шпаргалка по ро](cheatSheet/README_RU.md) 7 | * [Урок 0 -- Среда разработки](00-DeveloperEnvironment/README_RU.md) 8 | 9 | ### Модуль 1 10 | 11 | * [урок 1 -- Отправка сообщений и стандартный OUT](01-SendingAndStandardOut/README_RU.md) 12 | * [урок 2 -- Получение сообщений](02-Receiving/README_RU.md) 13 | * [урок 3 -- Сломанный телефон, Имена и Процессы](03-TelephoneNamesAndProcesses/README_RU.md) 14 | * [урок 4 -- Персистивная отправка и Подглядки](04-PersistentSendAndPeek/README_RU.md) 15 | * [урок 5 -- Оператор Объединения](05-JoinOperator/README_RU.md) 16 | 17 | ### Модуль 2 18 | * [урок 6 -- Неподделаевымые имена и Подтверждения](06-UnforgeableNamesAndAcks/) 19 | * [урок 7 -- Связки](07-Bundles/) 20 | * [урок 8 -- Каналы состояний и Методы](08-StateChannelsAndMethods/) 21 | * [урок 9 -- Объектные возможности](09-ObjectCapabilities/) 22 | * [урок 10 -- Опять синтаксис](10-MoreSyntax/) 23 | 24 | ### Модуль 3 25 | * [урок 11 --Сопоставление паттернов](11-PatternMatching/) 26 | * [урок 12 -- Структуры данных](12-DataStructures/) 27 | 28 | ### В работе 29 | * [урок 13 -- Итерации](13-Iteration/) 30 | 31 | ## Целевая аудитория 32 | Даже самого поверхностного знания о языках программирования, таких как python или javascript, достаточно, чтобы овладеть ро. Если вы вообще никогда не программировали, то некоторые моменты могут оказаться для вас непонятными. Однако никакие специальные знания в теории вычислений и алгоритмах не требуются для того, чтобы использовать данный туториал. 33 | 34 | ## Дополнительная информация 35 | * [Mike Stay's Rholang Tutorial](https://developer.rchain.coop/tutorial/) 36 | * [The Core team's tutorial](https://github.com/rchain/rchain/blob/master/docs/rholang/rholangtut.md) 37 | * С автором можно связаться через [его вебсайт](https://joshyorndorff.com/contact). 38 | 39 | ## Автор и лицензия 40 | Написано, по большей части, Joshy Orndorff при поддержке кооператива RChain. 41 | Иллюстрации Julianne Coxe. 42 | 43 | Публикуется под лицензией Apache 2.0 license. 44 | -------------------------------------------------------------------------------- /cheatSheet/README.md: -------------------------------------------------------------------------------- 1 | # Rholang Cheat Sheet 2 | 3 | Download as [pdf](RholangCheetSheet_10.04.18.pdf) [png](RholangCheetSheet_10.04.18.png) [jpg](RholangCheetSheet_10.04.18.jpg) 4 | ![Rendered cheat sheet](RholangCheetSheet_10.04.18.png) 5 | 6 | # Errata 7 | 8 | ## Boolean Operators 9 | `and` `or` `not` 10 | 11 | ## Crypto Channels 12 | `secp256k1Verify` 13 | `ed25519Verify` 14 | Arguments: Data, signature, pubkey, return 15 | 16 | `keccak256Hash` 17 | `sha256Hash` 18 | Arguments: Data, return 19 | 20 | ## Anti-Shadowing Operators 21 | `=` `*=` Derek, What's the difference between these? 22 | 23 | ## Channel Nomenclature 24 | The word "name" is heavily overloaded in rholang world. I've tried to start using "channel" in the context of the circle diagram. Should we update that, or is "name" permanently stuck in our vocab? 25 | -------------------------------------------------------------------------------- /cheatSheet/RholangCheetSheet_10.04.18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/cheatSheet/RholangCheetSheet_10.04.18.jpg -------------------------------------------------------------------------------- /cheatSheet/RholangCheetSheet_10.04.18.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/cheatSheet/RholangCheetSheet_10.04.18.pdf -------------------------------------------------------------------------------- /cheatSheet/RholangCheetSheet_10.04.18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/cheatSheet/RholangCheetSheet_10.04.18.png -------------------------------------------------------------------------------- /converter/README.md: -------------------------------------------------------------------------------- 1 | # Convert tutorial md files into html 2 | 3 | cd into a lesson folder 4 | 5 | run node ../converter/index.js index.md 6 | 7 | The output is in ./index.html 8 | 9 | https://marked.js.org/#/USING_PRO.md 10 | -------------------------------------------------------------------------------- /converter/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | var marked = require('marked') 4 | var renderer = new marked.Renderer(); 5 | var fs = require('fs') 6 | 7 | 8 | ///////////////////////// 9 | renderer.link = function(href, title, text) { 10 | 11 | if (text.substring(text.length - 4) !== ".rho"){ 12 | return `${text}` 13 | } 14 | var code = fs.readFileSync(href) 15 | 16 | 17 | return `
${code}
` 18 | } 19 | 20 | renderer.code = function(code, language, escaped){ 21 | return `
${code}
` 22 | } 23 | 24 | 25 | 26 | //////////////////////////////////// 27 | 28 | 29 | var filename = process.argv[2] 30 | var markdown = fs.readFileSync(filename, 'utf-8') 31 | 32 | var html = marked(markdown, { renderer: renderer }) 33 | var outFileName = filename.substring(0, filename.length - 3) + ".html" 34 | fs.writeFile(outFileName, html, err => {if(err) throw err}) 35 | -------------------------------------------------------------------------------- /converter/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rholang-tutorial-renderer", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "fs": { 8 | "version": "0.0.1-security", 9 | "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", 10 | "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" 11 | }, 12 | "marked": { 13 | "version": "0.6.1", 14 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.1.tgz", 15 | "integrity": "sha512-+H0L3ibcWhAZE02SKMqmvYsErLo4EAVJxu5h3bHBBDvvjeWXtl92rGUSBYHL2++5Y+RSNgl8dYOAXcYe7lp1fA==" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /converter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rholang-tutorial-renderer", 3 | "version": "1.0.0", 4 | "description": "Render rholang tutorial from markdown to rholang", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "rholang", 11 | "rchain", 12 | "learn", 13 | "tutorial", 14 | "markdown" 15 | ], 16 | "author": "Joshy Orndorff", 17 | "license": "ISC", 18 | "dependencies": { 19 | "fs": "0.0.1-security", 20 | "marked": "^0.6.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /none.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshOrndorff/LearnRholangByExample/9267c6ad95930362e3dc5ae7b9c94409eeac0261/none.jpg --------------------------------------------------------------------------------