{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# RChain Python gRPC client " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- This notebook is available at http://j.mp/rchain-py-grpc-walk-through" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- github https://github.com/proof-media/rchain-grpc\n", "- pypi https://pypi.org/user/proof-media/" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Introduction" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### How to reproduce this demo\n", "\n", "- Interactive locally\n", "- Read-only mode on the web" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Locally on your workstation \n", "with Docker containers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```bash\n", "git clone https://github.com/proof-media/rchain-notebook.git\n", "cd rchain-notebook\n", "docker-compose up\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Then open http://localhost:8888" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'prooflikesrchainalot'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# password is set in the `.env` file\n", "# and shared to notebook container\n", "%env NOTEBOOK_PASSWORD" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Read only mode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Through https://nbviewer.jupyter.org/\n", "\n", "- [link to notebook](https://github.com/proof-media/rchain-notebook/blob/testing/name-registry/notebooks/walk-through.ipynb)\n", "- [link to slides](https://nbviewer.jupyter.org/format/slides/github/proof-media/rchain-notebook/blob/testing%2Fname-registry/notebooks/walk-through.ipynb#/)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Proof platform\n", "\n", "![proof image](https://i0.wp.com/proofmedia.io/wp-content/uploads/2018/06/Default-Logo-copyxhdpi.png?resize=246%2C159&ssl=1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Because Truth Matters**\n", "\n", "https://proofmedia.io/" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> We are building a platform which leverages the wisdom of the crowds to establish truth." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- people vote in our platform on articles for being Mostly True/False\n", "- users bet tokens to rank their conviction \n", "- voting closes when we reach some parameters that are proven to make \"the crowd wise\"\n", "- tallying the vote will find out what the *majority* says\n", "- we use the blockchain to lock the tokens and provide cryptographic proofs that votes weren't tampered" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Rchain is needed to *register* tokens/hashes computed \n", "\n", "when each user votes" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Credits" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Our backend is based on `Python 3.7+` and `Django framework`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- inspired by the official rchain/python snippet \n", "\n", "https://github.com/rchain/rchain/tree/dev/node-client\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- developed mainly by Mateusz (a.k.a. `beetleman`)\n", "\n", "https://github.com/proof-media/rchain-grpc/graphs/contributors" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- I'm Paolo - CTO @Proof\n", "- Pythonista \n", "- Python teacher using Jupyter Notebooks" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Roadmap and status" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rchain-grpc (0.0.10) - python client to rchain gRPC\r\n" ] } ], "source": [ "! pip search rchain | grep -i grpc" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Up to version `0.0.10` -> code developed tested with `RNode 0.6.x`\n", "* Upcoming `0.0.11` release -> compatible with `RNode 0.7.x`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Current [update to 0.7 PR](https://github.com/proof-media/rchain-grpc/pull/10) is blocked by a [protobuf issue](https://github.com/protocolbuffers/protobuf/issues/5272)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Eval/Repl [not working](https://github.com/proof-media/rchain-grpc/issues/12) for gRPC missing definition\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Short-term goal\n", "\n", "move the repo into `rchain` GitHub space, see [issue](https://github.com/proof-media/rchain-grpc/issues/8)\n", "\n", "(after those previous problems are solved)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Using the code" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Connecting" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "With current `docker-compose` for the notebook you are running a RNode *standalone* instance" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# we have the OS NODE_NAME variable holding the other container name\n", "RNODE_HOST = %env NODE_NAME" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz\n", "fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz\n", "(1/1) Installing curl (7.61.1-r0)\n", "\u001b7 0% \u001b8\u001b[0K\u001b7100% ██████████████████████████████████████████████████████████████████████████\u001b8\u001b[0KExecuting busybox-1.28.4-r1.trigger\n", "OK: 36 MiB in 48 packages\n" ] } ], "source": [ "! apk add curl" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/bin/sh: curl: not found\r\n" ] } ], "source": [ "! curl $RNODE_HOST:40403/version" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Now we can open a channel through `gRPC` against the RChain node \n", "\n", "using the Python library!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "NOTE: in running docker image the package is already installed,\n", "\n", "while normally you would do:\n", "```bash\n", "pip install rchain-grpc\n", "```" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from rchain_grpc import casper\n", "\n", "connection = casper.create_connection(host=RNODE_HOST)\n", "connection" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Write Rholang code" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "In a notebook you can write a file like this" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing hello_world.rho\n" ] } ], "source": [ "%%file hello_world.rho\n", "\n", "new print(`rho:io:stdout`) in {\n", " print!(\"Hello World!\")\n", "}\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Then edit it inside the notebook server,\n", "e.g. link to file" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# then read the file to use the code in python\n", "with open('hello_world.rho') as fh:\n", " rholang_code = fh.read()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# alternative: write directly the code with triple quoted strings\n", "rholang_code = \"\"\"\n", "new print(`rho:io:stdout`) in {\n", " print!(\"Hello World!\")\n", "}\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "new print(`rho:io:stdout`) in {\n", " print!(\"Hello World!\")\n", "}\n", "\n" ] } ], "source": [ "print(rholang_code)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Deploy and propose" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "{'success': True, 'message': 'Success!'}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "casper.deploy(connection, rholang_code)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "{'success': True, 'message': 'Success! Block 4b15fa7621... created and added.'}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "casper.propose(connection)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Now check logs of the rnode to see if we have `Hello World!` string" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Play with blocks" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[{'blockHash': '4b15fa762195810bcc89a8db188927a4f1517f9a0d175f06b468908fb4bde506',\n", " 'blockSize': '1340',\n", " 'blockNumber': 1,\n", " 'deployCount': 1,\n", " 'tupleSpaceHash': '781bbcd09fa259caa17bab1c2d6b339c5bee99576bc04c8c012e5c06a9a0316c',\n", " 'timestamp': 1540215055121,\n", " 'faultTolerance': -1.0,\n", " 'mainParentHash': '8d08dd96ef1152951b80b551fb1bfb928f0a5e46742038da52c2be39e5f16d26',\n", " 'parentsHashList': ['8d08dd96ef1152951b80b551fb1bfb928f0a5e46742038da52c2be39e5f16d26'],\n", " 'sender': 'eabe5a1a0750d2a8745709bb0bdb24f63c6a8ac3a887b9bed40b34b0598ddf08'}]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "output = casper.get_blocks(connection, depth=1)\n", "\n", "# NOTE: protobuf outputs are always converted into Python dictionaries by our library\n", "output" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'4b15fa762195810bcc89a8db188927a4f1517f9a0d175f06b468908fb4bde506'" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block_hash = output.pop().get('blockHash')\n", "block_hash" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "{'blockHash': '4b15fa762195810bcc89a8db188927a4f1517f9a0d175f06b468908fb4bde506',\n", " 'blockSize': '1340',\n", " 'blockNumber': 1,\n", " 'deployCount': 1,\n", " 'tupleSpaceHash': '781bbcd09fa259caa17bab1c2d6b339c5bee99576bc04c8c012e5c06a9a0316c',\n", " 'tupleSpaceDump': '@{Unforgeable(0xa4fd447dedfc960485983ee817632cf36d79f45fd1796019edfb4a84a81d1697)}!({}) |\\n@{\"proofOfStake\"}!(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f)) |\\n@{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!(1222) |\\n@{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)}!({5122eac8a5c99b7da8f6d40d5f3269c6844dabde0418749ece2aeedc64c27703 : (288, \"secp256k1Verify\", Nil, 1), 5a3fff1ed432237e779fc6aa20d7549d043cc0dd92180ebee0346229598870f8 : (228, \"secp256k1Verify\", Nil, 2), d6b0c603a51fbcd56db1606a0591310876f93bdbf2309c7bdbc277a080368990 : (188, \"secp256k1Verify\", Nil, 4), a3158195b3ca6dfb88b8f0cb0788b01f25ea11421104df071bd043ca27f2def4 : (202, \"secp256k1Verify\", Nil, 3), e84b0ca96139b9c5e1a58b55e9d84682318a2030eaf24923204a1473ed659b34 : (224, \"secp256k1Verify\", Nil, 5), eabe5a1a0750d2a8745709bb0bdb24f63c6a8ac3a887b9bed40b34b0598ddf08 : (92, \"secp256k1Verify\", Nil, 6)}) |\\n@{Unforgeable(0x151d45b278f53a0ffcd58a40ff6ed0e1a6298592932844bb95b8574dd02fdd69)}!!(1) |\\nfor( @{x0} <= @{\"MakeMint\"} ) {\\n new x1, x2, x3 in {\\n @{x0}!(x1) |\\n for( @{x4}, @{x5} <= @{(x1, \"makePurse\")} ) {\\n new x6 in {\\n @{(\"MakeMint\", \"int2NN\")}!(x4, x6) |\\n for( @{x7} <- @{x6} ) {\\n @{x2}!(x7, x5)\\n }\\n }\\n } |\\n for( @{x4}, @{x5} <= @{x2} ) {\\n new x6 in {\\n @{x5}!(x6) |\\n for( @{x7}, @{x8}, @{x9} <= @{(x6, \"deposit\")} ) {\\n new x10 in {\\n @{(x8, x3)}!(x7, x10) |\\n for( @{x11} <- @{x10} ) {\\n match x11 {\\n true => @{(x4, \"add\")}!(x7, x9) ;\\n false => @{x9}!(false)\\n }\\n }\\n }\\n } |\\n for( @{x7} <= @{(x6, \"getBalance\")} ) {\\n @{(x4, \"value\")}!(x7)\\n } |\\n for( @{x7}, @{x8} <= @{(x6, \"split\")} ) {\\n new x9, x10 in {\\n @{(x6, \"sprout\")}!(x9) |\\n for( @{x11} <- @{x9} ) {\\n @{(x11, \"deposit\")}!(x7, x6, x10) |\\n for( @{x12} <- @{x10} ) {\\n match x12 {\\n true => @{x8}!([x11]) ;\\n false => @{x8}!([])\\n }\\n }\\n }\\n }\\n } |\\n for( @{x7} <= @{(x6, \"sprout\")} ) {\\n @{(x1, \"makePurse\")}!(0, x7)\\n } |\\n for( @{x7}, @{x8} <= @{(x6, x3)} ) {\\n @{(x4, \"sub\")}!(x7, x8)\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0} <= @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"getBalance\")} ) {\\n @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"value\")}!(x0)\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3}, @{x4} <= @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"bond\")} ) {\\n new x5, x6, x7, x8 in {\\n @{Unforgeable(0xcca5b98e5dbcc18b0dbee1d0d647ebcbac28938528f094486663746af39592df)}!(x2, x6) |\\n for( @{x9}, @{x10} <- @{x7} ) {\\n new x11 in {\\n @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"isBonded\")}!(x0, x11) |\\n for( @{x12} <- @{x11} ) {\\n match x12 {\\n true => @{x10}!((\"Left\", (\"Public key ${pk} already bonded.\" %% {\"pk\" : x0}))) ;\\n false => @{x10}!((\"Right\", x9))\\n }\\n }\\n }\\n } |\\n for( @{x9} <- @{x6} ) {\\n match x9 {\\n (\"Right\", (x10, x11)) => @{(\"Either\", \"compose\")}!(x10, [(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"validateBondAmount\"), (Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"validateBondingRate\"), x7, x8], x5) |\\n for( @{_}, @{x12} <- @{x8} ) {\\n @{Unforgeable(0x4f306dc2c8ec82696544fad1a6c23266314e18f706c3766b985af7e783bc6092)}!(x10, x11, x12)\\n } |\\n for( @{x12} <- @{x5} ) {\\n match x12 {\\n (\"Right\", _) => @{Unforgeable(0x85402e07e431f7f07b6816ce4c3a8ac8e32b268baf90b9e413c5d918b91b3719)}!(x0, x1, x11, x3, x4) ;\\n (\"Left\", x13) => @{(x2, \"deposit\")}!(x11, x10, x5) |\\n for( @{_} <- @{x5} ) {\\n @{x4}!((false, x13))\\n }\\n }\\n } ;\\n (\"Left\", x10) => @{x4}!((false, x10))\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{\"BasicWallet\"} ) {\\n new x4 in {\\n for( @{x5} <- @{x4} ) {\\n match x5 {\\n [] => @{x3}!([]) ;\\n [x6] => new x7, x8, x9 in {\\n @{x9}!(-1) |\\n @{x3}!([x7]) |\\n for( @{x10}, @{x11}, @{x12} <= @{(x7, \"deposit\")} ) {\\n @{(x0, \"deposit\")}!(x10, x11, x12)\\n } |\\n for( @{x10} <= @{(x7, \"getBalance\")} ) {\\n @{(x0, \"getBalance\")}!(x10)\\n } |\\n for( @{x10} <= @{(x7, \"getNonce\")} ) {\\n for( @{x11} <- @{x9} ) {\\n @{x10}!(x11) |\\n @{x9}!(x11)\\n }\\n } |\\n for( @{x10}, @{x11}, @{x12}, @{x13}, @{x14} <= @{(x7, \"transfer\")} ) {\\n new x15 in {\\n @{x8}!(x11, x10, x13, x12, x15) |\\n for( @{x16} <- @{x15} ) {\\n match x16 {\\n true => new x17 in {\\n @{(x0, \"split\")}!(x10, x17) |\\n for( @{x18} <- @{x17} ) {\\n match x18 {\\n [] => @{x14}!(\"Overdraft\") ;\\n [x19] => @{x14}!(\"Success\") |\\n @{x13}!(x19)\\n }\\n }\\n } ;\\n false => @{x14}!(\"Invalid signature or nonce\")\\n }\\n }\\n }\\n } |\\n for( @{x10}, @{x11}, @{x12}, @{x13}, @{x14} <= @{x8} ) {\\n for( @{x15} <- @{x9} ) {\\n match (x10 == (x15 + 1)) {\\n true => new x16, x17 in {\\n @{\"blake2b256Hash\"}!(([x10, x11, x12]).toByteArray(), x17) |\\n for( @{x18} <- @{x17} ) {\\n @{x6}!(x18, (x13).hexToBytes(), (x2).hexToBytes(), x16) |\\n for( @{x19} <- @{x16} ) {\\n match x19 {\\n true => @{x14}!(true) |\\n @{x9}!(x10) ;\\n false => @{x14}!(false) |\\n @{x9}!(x15)\\n }\\n }\\n }\\n } ;\\n false => @{x14}!(false) |\\n @{x9}!(x15)\\n }\\n }\\n }\\n }\\n }\\n } |\\n match x1 {\\n \"ed25519\" => @{x4}!([\"ed25519Verify\"]) ;\\n \"secp256k1\" => @{x4}!([\"secp256k1Verify\"]) ;\\n _ => @{x4}!([])\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3}, @{x4} <= @{Unforgeable(0x85402e07e431f7f07b6816ce4c3a8ac8e32b268baf90b9e413c5d918b91b3719)} ) {\\n new x5, x6, x7 in {\\n for( @{x8} <- @{Unforgeable(0x151d45b278f53a0ffcd58a40ff6ed0e1a6298592932844bb95b8574dd02fdd69)} ; @{x9} <- @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)} ) {\\n @{Unforgeable(0xc1ecaf0168b913e5a5ff3aa785cd9dba308a4cda7d3bf89dc0e632d557b4e599)}!((x9).size(), x8, x5) |\\n for( @{x10} <- @{x5} ) {\\n @{x6}!(x9, x10, {}, x7) |\\n for( @{x11} <- @{x7} ) {\\n @{x4}!((true, \"Bond successful!\")) |\\n @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)}!((x11).set(x0,((x2 - x8), x1, x3, ((x9).size() + 1))))\\n }\\n }\\n } |\\n for( @{x8}, @{x9}, @{x10}, @{x11} <= @{x6} ) {\\n match x8 {\\n {x13 : (x14, x15, x16, x17)...x12} => @{x6}!(x12, x9, (x10).set(x13,((x14 + (x9).nth((x17 - 1))), x15, x16, x17)), x11) ;\\n _ => @{x11}!(x10)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{Unforgeable(0x4f306dc2c8ec82696544fad1a6c23266314e18f706c3766b985af7e783bc6092)} ) {\\n new x3 in {\\n @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"deposit\")}!(x1, x0, x3) |\\n for( @{x4} <- @{x3} ) {\\n match x4 {\\n true => @{x2}!((\"Right\", x0)) ;\\n false => @{x2}!((\"Left\", \"Deposit failed.\"))\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{\"blake2b256Hash\"} ) {\\n Nil\\n} |\\nfor( @{x0} <= @{Unforgeable(0x00)} ) {\\n Nil\\n} |\\nfor( @{x0} <= @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"sprout\")} ) {\\n @{(Unforgeable(0x27b2c01187ecb6461ca47aca42b7b6abc143c036ed2242b52b378a1cecf2b07c), \"makePurse\")}!(0, x0)\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"parMap\")} ) {\\n new x3, x4, x5 in {\\n @{(\"ListOps\", \"map\")}!(x0, x4, x3) |\\n for( @{x6} <- @{x3} ) {\\n @{(\"ListOps\", \"map\")}!(x6, x5, x2)\\n } |\\n for( @{x6}, @{x7} <= @{x5} ) {\\n for( @{x8} <- @{x6} ) {\\n @{x7}!(x8)\\n }\\n } |\\n for( @{x6}, @{x7} <= @{x4} ) {\\n new x8 in {\\n @{x7}!(x8) |\\n @{x1}!(x6, x8)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{\"BasicWalletFaucet\"} ) {\\n new x2 in {\\n @{x1}!(x2) |\\n for( @{x3}, @{x4}, @{x5}, @{x6} <= @{x2} ) {\\n new x7 in {\\n @{(x0, \"makePurse\")}!(x3, x7) |\\n for( @{x8} <- @{x7} ) {\\n @{\"BasicWallet\"}!(x8, x4, x5, x6)\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{(\"ListOps\", \"fold\")} ) {\\n new x4 in {\\n for( @{x5}, @{x6}, @{x7} <= @{x4} ) {\\n new x8 in {\\n @{x2}!(x5, x6, x8) |\\n for( @{x9} <- @{x8} ) {\\n @{x7}!(false, x9)\\n }\\n }\\n } |\\n new x5 in {\\n @{(\"ListOps\", \"partialFold\")}!(x0, x1, x4, x5) |\\n for( @{_}, @{x6} <- @{x5} ) {\\n @{x3}!(x6)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0x03)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"unorderedParMap\")} ) {\\n new x3, x4, x5, x6, x7 in {\\n for( @{x8} <= @{x4} ) {\\n for( @{x9} <- @{x7} ; @{x10} <- @{x6} ; @{x11} <- @{x5} ) {\\n @{x5}!(x11) |\\n match (x11 == (x10 + 1)) {\\n true => @{(\"ListOps\", \"prepend\")}!(x8, x9, x2) ;\\n false => @{(\"ListOps\", \"prepend\")}!(x8, x9, x7) |\\n @{x6}!((x10 + 1))\\n }\\n }\\n } |\\n for( @{x8}, @{x9} <= @{x3} ) {\\n match x8 {\\n [x11...x10] => new x12 in {\\n @{x3}!(x10, (x9 + 1)) |\\n @{x1}!(x11, x12) |\\n for( @{x13} <- @{x12} ) {\\n @{x4}!(x13)\\n }\\n } ;\\n _ => @{x5}!(x9)\\n }\\n } |\\n match x0 {\\n [] => @{x2}!([]) ;\\n _ => @{x7}!([]) |\\n @{x6}!(0) |\\n @{x3}!(x0, 0)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"map\")} ) {\\n new x3 in {\\n @{(\"ListOps\", \"fold\")}!(x0, [], x3, x2) |\\n for( @{x4}, @{x5}, @{x6} <= @{x3} ) {\\n new x7 in {\\n @{x1}!(x4, x7) |\\n for( @{x8} <- @{x7} ) {\\n @{(\"ListOps\", \"append\")}!(x5, x8, x6)\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"isBonded\")} ) {\\n for( @{x2} <- @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)} ) {\\n @{x1}!((x2).contains(x0)) |\\n @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)}!(x2)\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{\"NonNegativeNumber\"} ) {\\n new x2, x3 in {\\n @{x1}!(x2) |\\n for( @{x4}, @{x5} <= @{(x2, \"add\")} ) {\\n match (x4 >= 0) {\\n true => for( @{x6} <- @{x3} ) {\\n match ((x6 + x4) > x6) {\\n true => @{x5}!(true) |\\n @{x3}!((x6 + x4)) ;\\n false => @{x5}!(false) |\\n @{x3}!(x6)\\n }\\n } ;\\n false => @{x5}!(false)\\n }\\n } |\\n for( @{x4}, @{x5} <= @{(x2, \"sub\")} ) {\\n match (x4 >= 0) {\\n true => for( @{x6} <- @{x3} ) {\\n match (x4 <= x6) {\\n true => @{x5}!(true) |\\n @{x3}!((x6 - x4)) ;\\n false => @{x5}!(false) |\\n @{x3}!(x6)\\n }\\n } ;\\n false => @{x5}!(false)\\n }\\n } |\\n for( @{x4} <= @{(x2, \"value\")} ) {\\n for( @{x5} <- @{x3} ) {\\n @{x4}!(x5) |\\n @{x3}!(x5)\\n }\\n } |\\n match (x0 >= 0) {\\n true => @{x3}!(x0) ;\\n _ => @{x3}!(0)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(\"WalletCheck\", \"create\")} ) {\\n new x2 in {\\n @{x2}!(false) |\\n for( @{[x3, x4]}, @{x5} <= @{x0} ) {\\n for( @{x6} <- @{x2} ) {\\n match x6 {\\n true => @{x4}!([false, \"Already claimed wallet\"]) |\\n @{x2}!(x6) ;\\n false => new x7, x8, x9 in {\\n @{\"keccak256Hash\"}!(([x3, x4]).toByteArray(), x9) |\\n for( @{x10} <- @{x9} ) {\\n @{\"secp256k1Verify\"}!(x10, (x5).hexToBytes(), ((\"04\" ++ x3)).hexToBytes(), x7) |\\n for( @{x11} <- @{x7} ) {\\n match x11 {\\n true => @{(\"WalletCheck\", \"publicToAddr\")}!(x3, x8) |\\n for( @{x12} <- @{x8} ) {\\n match (x12 == ((x0).slice(2,(x0).length())).hexToBytes()) {\\n true => new x13 in {\\n @{\"BasicWallet\"}!(x1, \"secp256k1\", (\"04\" ++ x3), x13) |\\n @{x2}!(true) |\\n for( @{[x14]} <- @{x13} ) {\\n @{x4}!([true, x14]) |\\n @{x3}!!(x14)\\n }\\n } ;\\n false => @{x4}!([false, \"Public key is not the preimage of hash\"]) |\\n @{x2}!(x6)\\n }\\n } ;\\n false => @{x4}!([false, \"Signature verification failed\"]) |\\n @{x2}!(x6)\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"split\")} ) {\\n new x2, x3 in {\\n @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"sprout\")}!(x2) |\\n for( @{x4} <- @{x2} ) {\\n @{(x4, \"deposit\")}!(x0, Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), x3) |\\n for( @{x5} <- @{x3} ) {\\n match x5 {\\n true => @{x1}!([x4]) ;\\n false => @{x1}!([])\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{\"secp256k1Verify\"} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0xb8e2ba52606495c0e8949645b55a7b8ad14dc3147041f14a98517c5ab9d0146f)} ) {\\n new x2 in {\\n @{x1}!(x2) |\\n for( @{x3}, @{x4}, @{x5} <= @{(x2, \"deposit\")} ) {\\n new x6 in {\\n @{(x4, Unforgeable(0xd498054223e4bf5c4bf037f2e4c0b9d93fe4eaa7e5051833be6558619f27ced8))}!(x3, x6) |\\n for( @{x7} <- @{x6} ) {\\n match x7 {\\n true => @{(x0, \"add\")}!(x3, x5) ;\\n false => @{x5}!(false)\\n }\\n }\\n }\\n } |\\n for( @{x3} <= @{(x2, \"getBalance\")} ) {\\n @{(x0, \"value\")}!(x3)\\n } |\\n for( @{x3}, @{x4} <= @{(x2, \"split\")} ) {\\n new x5, x6 in {\\n @{(x2, \"sprout\")}!(x5) |\\n for( @{x7} <- @{x5} ) {\\n @{(x7, \"deposit\")}!(x3, x2, x6) |\\n for( @{x8} <- @{x6} ) {\\n match x8 {\\n true => @{x4}!([x7]) ;\\n false => @{x4}!([])\\n }\\n }\\n }\\n }\\n } |\\n for( @{x3} <= @{(x2, \"sprout\")} ) {\\n @{(Unforgeable(0x27b2c01187ecb6461ca47aca42b7b6abc143c036ed2242b52b378a1cecf2b07c), \"makePurse\")}!(0, x3)\\n } |\\n for( @{x3}, @{x4} <= @{(x2, Unforgeable(0xd498054223e4bf5c4bf037f2e4c0b9d93fe4eaa7e5051833be6558619f27ced8))} ) {\\n @{(x0, \"sub\")}!(x3, x4)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"foreach\")} ) {\\n new x3, x4 in {\\n @{(\"ListOps\", \"fold\")}!(x0, Nil, x3, x4) |\\n for( @{_} <- @{x4} ) {\\n @{x2}!(true)\\n } |\\n for( @{x5}, @{x6}, @{x7} <= @{x3} ) {\\n new x8 in {\\n @{x1}!(x5, x8) |\\n for( @{_} <- @{x8} ) {\\n @{x7}!(Nil)\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0} <= @{(\"Rev\", \"makePurse\")} ) {\\n @{(Unforgeable(0x27b2c01187ecb6461ca47aca42b7b6abc143c036ed2242b52b378a1cecf2b07c), \"makePurse\")}!(0, x0)\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"range\")} ) {\\n new x3 in {\\n @{x3}!((x1 - 1), []) |\\n for( @{x4}, @{x5} <= @{x3} ) {\\n match (x4 < x0) {\\n true => @{x2}!(x5) ;\\n false => @{x3}!((x4 - 1), ([x4] ++ x5))\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{Unforgeable(0x0b)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{(\"ListOps\", \"reverse\")} ) {\\n @{(\"ListOps\", \"fold\")}!(x0, [], (\"ListOps\", \"prepend\"), x1)\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"Either\", \"compose\")} ) {\\n new x3 in {\\n @{(\"ListOps\", \"fold\")}!(x1, (\"Right\", x0), x3, x2) |\\n for( @{x4}, @{x5}, @{x6} <= @{x3} ) {\\n @{(\"Either\", \"flatMap\")}!(x5, x4, x6)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), \"deposit\")} ) {\\n new x3 in {\\n @{(x1, Unforgeable(0xd498054223e4bf5c4bf037f2e4c0b9d93fe4eaa7e5051833be6558619f27ced8))}!(x0, x3) |\\n for( @{x4} <- @{x3} ) {\\n match x4 {\\n true => @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"add\")}!(x0, x2) ;\\n false => @{x2}!(false)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"append\")} ) {\\n @{x2}!((x0 ++ [x1]))\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"prepend\")} ) {\\n @{x2}!(([x0] ++ x1))\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"Either\", \"map\")} ) {\\n match x0 {\\n (\"Right\", x3) => new x4 in {\\n @{x1}!(x3, x4) |\\n for( @{x5} <- @{x4} ) {\\n @{x2}!((\"Right\", x5))\\n }\\n } ;\\n (\"Left\", _) => @{x2}!(x0)\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{Unforgeable(0xc1ecaf0168b913e5a5ff3aa785cd9dba308a4cda7d3bf89dc0e632d557b4e599)} ) {\\n new x3, x4, x5, x6, x7, x8 in {\\n @{(\"ListOps\", \"range\")}!(1, (x0 + 1), x3) |\\n for( @{x9} <- @{x3} ) {\\n @{(\"ListOps\", \"map\")}!(x9, x4, x5) |\\n for( @{x10} <- @{x5} ) {\\n @{(\"ListOps\", \"fold\")}!(x10, 0, x6, x8) |\\n for( @{x11} <- @{x8} ) {\\n @{x2}!(([(((x10).nth(0) + x1) - x11)] ++ (x10).slice(1,x0)))\\n }\\n }\\n } |\\n for( @{x9}, @{x10}, @{x11} <= @{x6} ) {\\n @{x11}!((x9 + x10))\\n } |\\n for( @{x9}, @{x10} <= @{x4} ) {\\n @{x10}!((2 * x1) * ((x0 + 1) - x9) / (x0 * (x0 + 1)))\\n }\\n }\\n} |\\nfor( @{x0} <= @{Unforgeable(0x02)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0xcca5b98e5dbcc18b0dbee1d0d647ebcbac28938528f094486663746af39592df)} ) {\\n new x2, x3 in {\\n @{(x0, \"getBalance\")}!(x2) |\\n for( @{x4} <- @{x2} ) {\\n @{(x0, \"split\")}!(x4, x3) |\\n for( @{x5} <- @{x3} ) {\\n match x5 {\\n [] => @{x1}!((\"Left\", \"Could not extract funds from given purse\")) ;\\n [x6] => @{x1}!((\"Right\", (x6, x4)))\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"sub\")} ) {\\n match (x0 >= 0) {\\n true => for( @{x2} <- @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)} ) {\\n match (x0 <= x2) {\\n true => @{x1}!(true) |\\n @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!((x2 - x0)) ;\\n false => @{x1}!(false) |\\n @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!(x2)\\n }\\n } ;\\n false => @{x1}!(false)\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0x09)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"validateBondAmount\")} ) {\\n new x2 in {\\n @{(x0, \"getBalance\")}!(x2) |\\n for( @{x3} <- @{x2} ; @{x4} <- @{Unforgeable(0x151d45b278f53a0ffcd58a40ff6ed0e1a6298592932844bb95b8574dd02fdd69)} ) {\\n match ((x3 - x4) < 1) {\\n true => @{x1}!((\"Left\", \"Bond less than minimum!\")) ;\\n false => match ((x3 - x4) > 9223372036854775807) {\\n true => @{x1}!((\"Left\", \"Bond greater than maximum!\")) ;\\n false => @{x1}!((\"Right\", x0))\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0x27b2c01187ecb6461ca47aca42b7b6abc143c036ed2242b52b378a1cecf2b07c), \"makePurse\")} ) {\\n new x2 in {\\n @{(\"MakeMint\", \"int2NN\")}!(x0, x2) |\\n for( @{x3} <- @{x2} ) {\\n @{Unforgeable(0xb8e2ba52606495c0e8949645b55a7b8ad14dc3147041f14a98517c5ab9d0146f)}!(x3, x1)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0xc0e1db8bd0baabd4e0ecca7ec9804b6e53e3fc8ed0179b9272bd8291286bed41), Unforgeable(0xd498054223e4bf5c4bf037f2e4c0b9d93fe4eaa7e5051833be6558619f27ced8))} ) {\\n @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"sub\")}!(x0, x1)\\n} |\\nfor( @{x0}, @{x1} <= @{(\"MakeMint\", \"int2NN\")} ) {\\n new x2 in {\\n @{\"NonNegativeNumber\"}!(x0, x2) |\\n for( @{x3} <- @{x2} ) {\\n @{x1}!(x3)\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"Either\", \"flatMap\")} ) {\\n match x0 {\\n (\"Right\", x3) => @{x1}!(x3, x2) ;\\n (\"Left\", _) => @{x2}!(x0)\\n }\\n} |\\nfor( @{x0} <= @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"getBonds\")} ) {\\n for( @{x1} <- @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)} ) {\\n @{x0}!(x1) |\\n @{Unforgeable(0x51ff32c8ed4b7b774ab5fe0c5e4f7e3b5bd4bdf31903ddf8e5ca65c6aa4070b5)}!(x1)\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{\"sha256Hash\"} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0x01)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1} <= @{(\"WalletCheck\", \"publicToAddr\")} ) {\\n new x2 in {\\n @{\"keccak256Hash\"}!((x0).hexToBytes(), x2) |\\n for( @{x3} <- @{x2} ) {\\n @{x1}!((x3).slice(12,32))\\n }\\n }\\n} |\\nfor( @{x0} <= @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"value\")} ) {\\n for( @{x1} <- @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)} ) {\\n @{x0}!(x1) |\\n @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!(x1)\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{(\"ListOps\", \"partialFold\")} ) {\\n new x4 in {\\n @{x4}!(x1, x0) |\\n for( @{x5}, @{x6} <= @{x4} ) {\\n match x6 {\\n [x8...x7] => new x9 in {\\n @{x2}!(x8, x5, x9) |\\n for( @{x10}, @{x11} <- @{x9} ) {\\n match x10 {\\n true => @{x3}!(x10, x11) ;\\n false => @{x4}!(x11, x7)\\n }\\n }\\n } ;\\n _ => @{x3}!(false, x5)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0xc02c72fad36bc255f9f93a5b569d4d2bd502bed3fe6ed37534a544113c1e4e3f), \"validateBondingRate\")} ) {\\n @{x1}!((\"Right\", x0))\\n} |\\nfor( @{x0}, @{x1} <= @{Unforgeable(0x0a)} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"zip\")} ) {\\n new x3 in {\\n @{x3}!((x0, x1), [], x2) |\\n for( @{x4}, @{x5}, @{x6} <= @{x3} ) {\\n match x4 {\\n ([x8...x7], [x10...x9]) => @{x3}!((x7, x9), (x5 ++ [(x8, x10)]), x6) ;\\n _ => @{x6}!(x5)\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3}, @{x4} <= @{\"MakePoS\"} ) {\\n new x5, x6, x7, x8, x9, x10, x11 in {\\n @{x6}!(x3) |\\n @{x4}!(x5) |\\n @{x7}!!(x1) |\\n for( @{x12}, @{x13}, @{x14}, @{x15}, @{x16} <= @{(x5, \"bond\")} ) {\\n new x17, x18, x19, x20 in {\\n @{x8}!(x14, x18) |\\n for( @{x21}, @{x22} <- @{x19} ) {\\n new x23 in {\\n @{(x5, \"isBonded\")}!(x12, x23) |\\n for( @{x24} <- @{x23} ) {\\n match x24 {\\n true => @{x22}!((\"Left\", (\"Public key ${pk} already bonded.\" %% {\"pk\" : x12}))) ;\\n false => @{x22}!((\"Right\", x21))\\n }\\n }\\n }\\n } |\\n for( @{x21} <- @{x18} ) {\\n match x21 {\\n (\"Right\", (x22, x23)) => @{(\"Either\", \"compose\")}!(x22, [(x5, \"validateBondAmount\"), (x5, \"validateBondingRate\"), x19, x20], x17) |\\n for( @{_}, @{x24} <- @{x20} ) {\\n @{x9}!(x22, x23, x24)\\n } |\\n for( @{x24} <- @{x17} ) {\\n match x24 {\\n (\"Right\", _) => @{x10}!(x12, x13, x23, x15, x16) ;\\n (\"Left\", x25) => @{(x14, \"deposit\")}!(x23, x22, x17) |\\n for( @{_} <- @{x17} ) {\\n @{x16}!((false, x25))\\n }\\n }\\n } ;\\n (\"Left\", x22) => @{x16}!((false, x22))\\n }\\n }\\n }\\n } |\\n for( @{x12} <= @{(x5, \"getBonds\")} ) {\\n for( @{x13} <- @{x6} ) {\\n @{x12}!(x13) |\\n @{x6}!(x13)\\n }\\n } |\\n for( @{x12}, @{x13} <= @{(x5, \"isBonded\")} ) {\\n for( @{x14} <- @{x6} ) {\\n @{x13}!((x14).contains(x12)) |\\n @{x6}!(x14)\\n }\\n } |\\n for( @{x12}, @{x13} <= @{(x5, \"validateBondAmount\")} ) {\\n new x14 in {\\n @{(x12, \"getBalance\")}!(x14) |\\n for( @{x15} <- @{x14} ; @{x16} <- @{x7} ) {\\n match ((x15 - x16) < x1) {\\n true => @{x13}!((\"Left\", \"Bond less than minimum!\")) ;\\n false => match ((x15 - x16) > x2) {\\n true => @{x13}!((\"Left\", \"Bond greater than maximum!\")) ;\\n false => @{x13}!((\"Right\", x12))\\n }\\n }\\n }\\n }\\n } |\\n for( @{x12}, @{x13} <= @{(x5, \"validateBondingRate\")} ) {\\n @{x13}!((\"Right\", x12))\\n } |\\n for( @{x12}, @{x13}, @{x14} <= @{x11} ) {\\n new x15, x16, x17, x18, x19, x20 in {\\n @{(\"ListOps\", \"range\")}!(1, (x12 + 1), x15) |\\n for( @{x21} <- @{x15} ) {\\n @{(\"ListOps\", \"map\")}!(x21, x16, x17) |\\n for( @{x22} <- @{x17} ) {\\n @{(\"ListOps\", \"fold\")}!(x22, 0, x18, x20) |\\n for( @{x23} <- @{x20} ) {\\n @{x14}!(([(((x22).nth(0) + x13) - x23)] ++ (x22).slice(1,x12)))\\n }\\n }\\n } |\\n for( @{x21}, @{x22}, @{x23} <= @{x18} ) {\\n @{x23}!((x21 + x22))\\n } |\\n for( @{x21}, @{x22} <= @{x16} ) {\\n @{x22}!((2 * x13) * ((x12 + 1) - x21) / (x12 * (x12 + 1)))\\n }\\n }\\n } |\\n for( @{x12}, @{x13}, @{x14}, @{x15}, @{x16} <= @{x10} ) {\\n new x17, x18, x19 in {\\n for( @{x20} <- @{x7} ; @{x21} <- @{x6} ) {\\n @{x11}!((x21).size(), x20, x17) |\\n for( @{x22} <- @{x17} ) {\\n @{x18}!(x21, x22, {}, x19) |\\n for( @{x23} <- @{x19} ) {\\n @{x16}!((true, \"Bond successful!\")) |\\n @{x6}!((x23).set(x12,((x14 - x20), x13, x15, ((x21).size() + 1))))\\n }\\n }\\n } |\\n for( @{x20}, @{x21}, @{x22}, @{x23} <= @{x18} ) {\\n match x20 {\\n {x25 : (x26, x27, x28, x29)...x24} => @{x18}!(x24, x21, (x22).set(x25,((x26 + (x21).nth((x29 - 1))), x27, x28, x29)), x23) ;\\n _ => @{x23}!(x22)\\n }\\n }\\n }\\n } |\\n for( @{x12}, @{x13}, @{x14} <= @{x9} ) {\\n new x15 in {\\n @{(x0, \"deposit\")}!(x13, x12, x15) |\\n for( @{x16} <- @{x15} ) {\\n match x16 {\\n true => @{x14}!((\"Right\", x12)) ;\\n false => @{x14}!((\"Left\", \"Deposit failed.\"))\\n }\\n }\\n }\\n } |\\n for( @{x12}, @{x13} <= @{x8} ) {\\n new x14, x15 in {\\n @{(x12, \"getBalance\")}!(x14) |\\n for( @{x16} <- @{x14} ) {\\n @{(x12, \"split\")}!(x16, x15) |\\n for( @{x17} <- @{x15} ) {\\n match x17 {\\n [] => @{x13}!((\"Left\", \"Could not extract funds from given purse\")) ;\\n [x18] => @{x13}!((\"Right\", (x18, x16)))\\n }\\n }\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1}, @{x2}, @{x3} <= @{\"ed25519Verify\"} ) {\\n Nil\\n} |\\nfor( @{x0}, @{x1}, @{x2} <= @{(\"ListOps\", \"indexOf\")} ) {\\n new x3 in {\\n for( @{x4}, @{x5}, @{x6} <= @{x3} ) {\\n @{x6}!((x4 == x1), (x5 + 1))\\n } |\\n new x4 in {\\n @{(\"ListOps\", \"partialFold\")}!(x0, -1, x3, x4) |\\n for( @{x5}, @{x6} <- @{x4} ) {\\n match x5 {\\n true => @{x2}!(x6) ;\\n false => @{x2}!(-1)\\n }\\n }\\n }\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{(Unforgeable(0x2b6d3d1aeebe4f5cbffea98f589bc48516f3934851886f16c165190ea8ab62ef), \"add\")} ) {\\n match (x0 >= 0) {\\n true => for( @{x2} <- @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)} ) {\\n match ((x2 + x0) > x2) {\\n true => @{x1}!(true) |\\n @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!((x2 + x0)) ;\\n false => @{x1}!(false) |\\n @{Unforgeable(0x651923755db27e1ed7e69bd7b8576330a2d20c7b16253b46e71b5c1386b91e2d)}!(x2)\\n }\\n } ;\\n false => @{x1}!(false)\\n }\\n} |\\nfor( @{x0}, @{x1} <= @{\"keccak256Hash\"} ) {\\n Nil\\n}',\n", " 'timestamp': 1540215055121,\n", " 'faultTolerance': -1.0,\n", " 'mainParentHash': '8d08dd96ef1152951b80b551fb1bfb928f0a5e46742038da52c2be39e5f16d26',\n", " 'parentsHashList': ['8d08dd96ef1152951b80b551fb1bfb928f0a5e46742038da52c2be39e5f16d26'],\n", " 'sender': 'eabe5a1a0750d2a8745709bb0bdb24f63c6a8ac3a887b9bed40b34b0598ddf08',\n", " 'shardId': 'rchain'}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block = casper.get_block(connection, block_hash=block_hash)\n", "block" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block.get('blockNumber')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Context Manager" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The connection provided by the library can be used in a `with` python statement" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'success': True, 'message': 'Success! Block 40d0252c21... created and added.'}\n", "Current block number is 2\n", "with hash 40d0252c212fb57e09a812b8356d06926ead79becc86e4c4e02c6f3d543a275c\n" ] } ], "source": [ "# all previous operations in one context\n", "\n", "with casper.create_connection(host=RNODE_HOST) as connection:\n", "\n", " # deploy / propose\n", " casper.deploy(connection, rholang_code)\n", " print(casper.propose(connection))\n", " \n", " # handle output\n", " output = casper.get_blocks(connection, depth=1)\n", " block_hash = output.pop().get('blockHash')\n", " block = casper.get_block(connection, block_hash=block_hash)\n", " print(f\"Current block number is {block.get('blockNumber')}\\nwith hash {block_hash}\")\n", " \n", "# connection here is closed" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Interact with channels" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Now we'll take advantage of the `listenForDataAtName` functionality inside the RChain gRPC definition.\n", "\n", "We can specify a channel to receive the results of the new block proposed." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "output_placeholder = \"your_channel_name\"" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "rholang_code = f\"\"\"\n", "{output_placeholder}!(\"bar\")\n", "\"\"\" " ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "your_channel_name!(\"bar\")\n", "\n" ] } ], "source": [ "print(rholang_code)\n", "\n", "# your_channel_name will be replaced with @\"RANDOMNAME\"" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "with casper.create_connection(host=RNODE_HOST) as connection:\n", " block = casper.run_and_get_value_from(\n", " connection=connection,\n", " term=rholang_code, \n", " # this name gets replaced with a channel name\n", " output_placeholder=output_placeholder\n", " )" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'ack_b2859ffa8914757d71c63ff685b5b880f36f0a1e69952a7d1c2f23b44008'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# what's used for replacing the placeholder\n", "import secrets\n", "ack_name = f'ack_{secrets.token_hex(30)}'\n", "ack_name" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "{'status': 'Success',\n", " 'blockResults': [{'postBlockData': [['bar']],\n", " 'block': {'blockHash': '14e19feeba18e8840bd85e2dda5d7bf93066c10e228ebbffe0d9ad23f541d276',\n", " 'blockSize': '1144',\n", " 'blockNumber': 6,\n", " 'deployCount': 1,\n", " 'tupleSpaceHash': 'd7184933b08e4d3e23afc3451de901a4c6fe0507cff15f7349ecf6cf051a50a8',\n", " 'timestamp': 1540215534547,\n", " 'faultTolerance': -1.0,\n", " 'mainParentHash': '05ff25f824832ff5219e01be5eb4adeb05976ad5612d7b74981e2002915e708d',\n", " 'parentsHashList': ['05ff25f824832ff5219e01be5eb4adeb05976ad5612d7b74981e2002915e708d'],\n", " 'sender': 'eabe5a1a0750d2a8745709bb0bdb24f63c6a8ac3a887b9bed40b34b0598ddf08'}}],\n", " 'length': 1}" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "block" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Received: bar\n" ] } ], "source": [ "results = block.get('blockResults').pop()\n", "\n", "for message in results.get('postBlockData'):\n", " print(\"Received: \", message.pop())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Name registry\n", "\n", "`NEW!`\n", "\n", "(see [link to specs](https://rchain.atlassian.net/wiki/spaces/RHOL/pages/511541342/Name+registry+specification))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Using the techniques tested so far we can now:\n", "\n", "- write a contract with `unforgeable name`\n", "- register its name to Name Registry (introduced in 0.7) \n", "- and get the id for lookup\n", "\n", "so - all programmatically from Python - \n", "\n", "we can (almost) call a contract in a secure way." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 1. Register a contract" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "ack_name = 'placeholder_something'" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "rholang_code = \"\"\"\n", "new newName, ack, register(`rho:registry:insertArbitrary`), stdout(`rho:io:stdout`) in\n", "{\n", " register!(bundle+{*newName}, *ack)\n", " |\n", " contract newName(@msg) = {\n", " stdout!(\"Contract called with message: \" ++ msg)\n", " }\n", " |\n", " for (@msg <- ack) {\n", " %s!([\"From registry: \", msg])\n", " }\n", "}\n", "\"\"\" % ack_name" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "new newName, ack, register(`rho:registry:insertArbitrary`), stdout(`rho:io:stdout`) in\n", "{\n", " register!(bundle+{*newName}, *ack)\n", " |\n", " contract newName(@msg) = {\n", " stdout!(\"Contract called with message: \" ++ msg)\n", " }\n", " |\n", " for (@msg <- ack) {\n", " placeholder_something!([\"From registry: \", msg])\n", " }\n", "}\n", "\n" ] } ], "source": [ "print(rholang_code)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'blockResults': [{'block': {'blockHash': '8d40c550e9cd169c4bf80eb2d598835aed674f72becf933571d2406ea835a25e',\n", " 'blockNumber': 9,\n", " 'blockSize': '3185',\n", " 'deployCount': 1,\n", " 'faultTolerance': -1.0,\n", " 'mainParentHash': '40472937049565f99775e329dfdb334b5af4a362baf38138ea5b3cd836f2c3c8',\n", " 'parentsHashList': ['40472937049565f99775e329dfdb334b5af4a362baf38138ea5b3cd836f2c3c8'],\n", " 'sender': 'eabe5a1a0750d2a8745709bb0bdb24f63c6a8ac3a887b9bed40b34b0598ddf08',\n", " 'timestamp': 1540215840006,\n", " 'tupleSpaceHash': '2c0846b670edfd62a536b5e6cfa7307037c5144105f7676075f755f0a844b95c'},\n", " 'postBlockData': [[{'ps': [['From registry: '],\n", " ['rho:id:c1wqhooe5f9f8st4qe69zs7t5jrj8zszbx4zd51qu7pi5sdc6hh1iw']]}]]}],\n", " 'length': 1,\n", " 'status': 'Success'}\n" ] } ], "source": [ "# run and get the value in the block output\n", "with casper.create_connection(host=RNODE_HOST) as connection:\n", " block = casper.run_and_get_value_from(connection, rholang_code, ack_name)\n", " \n", "from pprint import pprint\n", "pprint(block)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 2. WIP: get ID inside the code" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We are looking to find a better way to handle the \"post block data\" " ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "post_block_data = block.get('blockResults').pop().get('postBlockData')" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[{'ps': [['From registry: '],\n", " ['rho:id:c1wqhooe5f9f8st4qe69zs7t5jrj8zszbx4zd51qu7pi5sdc6hh1iw']]}]]" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "post_block_data" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'rho:id:c1wqhooe5f9f8st4qe69zs7t5jrj8zszbx4zd51qu7pi5sdc6hh1iw'" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(post_block_data[0][0].values())[0][1][0]" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# alternative with json/regular expression\n", "\n", "import re\n", "import json\n", "\n", "post_block_str = json.dumps(post_block_data)\n", "\n", "match = re.search(r\"rho:id:[^\\\"]+\", post_block_str)\n", "registry_id = match.group()" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'rho:id:c1wqhooe5f9f8st4qe69zs7t5jrj8zszbx4zd51qu7pi5sdc6hh1iw'" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "registry_id" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### 3. Lookup and call the contract" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "new return, lookup(`rho:registry:lookup`), stdout(`rho:io:stdout`) in\n", "{\n", " lookup!(`rho:id:c1wqhooe5f9f8st4qe69zs7t5jrj8zszbx4zd51qu7pi5sdc6hh1iw`, *return) |\n", " for (myContract <- return) {\n", " myContract!(\"Proof test\")\n", " }\n", "}\n", "\n" ] } ], "source": [ "rholang_code = \"\"\"\n", "new return, lookup(`rho:registry:lookup`), stdout(`rho:io:stdout`) in\n", "{\n", " lookup!(`%s`, *return) |\n", " for (myContract <- return) {\n", " myContract!(\"Proof test\")\n", " }\n", "}\n", "\"\"\" % registry_id\n", "print(rholang_code)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'success': True, 'message': 'Success!'}\n", "{'success': True, 'message': 'Success! Block 06319c14c3... created and added.'}\n" ] } ], "source": [ "with casper.create_connection(host=RNODE_HOST) as connection:\n", " print(casper.deploy(connection, rholang_code))\n", " print(casper.propose(connection))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "go check the logs!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# THE END" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "239px" }, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }