Serpentを使ってEthereumのコントラクトコードを書く

# Serpentとは

* Serpent（サーペント：毒蛇）はPythonライクにEthereum（イーサリアム）のコントラクトを書くための言語
* Ethereum（イーサリアム）でコントラクトを実装する場合は、JavaScriptライクにコントラクトを書くことができるSolidityが圧倒的に流行っているのでSerpentは文献が少ない悲
* Ethereumの創設者であるVitalik Buterinはビットコインのライブラリ等（pybitcointools）をPythonで実装していたのでpython系を密かに応援していることを期待している

# インストール（pyethereum）

* まずはpyethereumをインストールした（私の環境はMax OS X）

```bash:
$ git clone https://github.com/ethereum/pyethereum
Cloning into 'pyethereum'...
remote: Counting objects: 12773, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 12773 (delta 0), reused 0 (delta 0), pack-reused 12761
Receiving objects: 100% (12773/12773), 4.48 MiB | 48.00 KiB/s, done.
Resolving deltas: 100% (9465/9465), done.
Checking connectivity... done.

$ cd pyethereum/

$ git checkout develop
Already on 'develop'
Your branch is up-to-date with 'origin/develop'.

$ pip install -r requirements.txt 
Collecting https://github.com/ethereum/ethash/tarball/master (from -r requirements.txt (line 9))
  Downloading https://github.com/ethereum/ethash/tarball/master
     - 92kB 89kB/s
　　：
　　：
 Running setup.py install for pyethash ... done
Successfully installed bitcoin-1.1.42 pbkdf2-1.3 pycryptodome-3.4 pyethash-0.1.23 pysha3-0.3 repoze.lru-0.6 rlp-0.4.6 scrypt-0.7.1 secp256k1-0.13.2

$ pythin setup.py install
Installed /private/var/folders/53/svs5z_nd1b98rlwp_nn5ybk80000gn/T/easy_install-chm3e1an/pytest-runner-2.7/.eggs/setuptools_scm-1.11.1-py3.5.egg
zip_safe flag not set; analyzing archive contents...

packages
Finished processing dependencies for ethereum==1.5.2
````

# インストール（serpent）

* 続いてserpentをインストールした（私の環境はMax OS X）

```bash:
$ git clone https://github.com/ethereum/serpent.git
Cloning into 'serpent'...
remote: Counting objects: 2053, done.
remote: Total 2053 (delta 0), reused 0 (delta 0), pack-reused 2053
Receiving objects: 100% (2053/2053), 3.38 MiB | 82.00 KiB/s, done.
Resolving deltas: 100% (1327/1327), done.
Checking connectivity... done.

$ cd serpent

$ git checkout develop
Branch develop set up to track remote branch develop from origin.
Switched to a new branch 'develop'

$ make && sudo make install
c++ -fPIC -Wno-sign-compare   -c -o keccak-tiny.o keccak-tiny.cpp
c++ -fPIC -Wno-sign-compare   -c -o bignum.o bignum.cpp
　：
　：

Installed /Users/abenben/.pyenv/versions/anaconda-2.2.0/lib/python2.7/site-packages/ethereum_serpent-2.0.2-py2.7-macosx-10.6-x86_64.egg
Processing dependencies for ethereum-serpent==2.0.2
Finished processing dependencies for ethereum-serpent==2.0.2
````

# サンプル動作の確認（その１）

以下の場所にあるサンプルの一部を動かしてみる
https://github.com/ethereum/wiki/wiki/Serpent

その他のサンプルは以下の場所に用意されている
https://github.com/ethereum/serpent/tree/master/examples

まずはserpentの簡単な実装を準備

```py:mul2.se
def double(x):
    return(x * 2)
```

コンパイル

```bash:
$ serpent compile mul2.se
604380600b600039604e567c010000000000000000000000000000000000000000000000000000000060003504636ffa1caa81141560415760043560405260026040510260605260206060f35b505b6000f3
```

コンパイル(pretty_compile)

```bash:
$ serpent pretty_compile mul2.se
[PUSH1, 67, DUP1, PUSH1, 11, PUSH1, 0, CODECOPY, 
PUSH1, 78, JUMP, PUSH29, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PUSH1, 0, 
CALLDATALOAD, DIV, PUSH4, 111, 250, 28, 170, DUP2, EQ, ISZERO, 
PUSH1, 65, JUMPI, PUSH1, 4, CALLDATALOAD, PUSH1, 64, MSTORE, 
PUSH1, 2, PUSH1, 64, MLOAD, MUL, PUSH1, 96, MSTORE, PUSH1, 32, 
PUSH1, 96, RETURN, JUMPDEST, POP, JUMPDEST, PUSH1, 0, RETURN]
```

LLL形式（LISP?）に変換

```bash:
$ serpent compile_to_lll mul2.se
(return 0 
  (lll 
    (with '__funid 
      (div (calldataload 0) 
        26959946667150639794667015087019630673637144422540572481103610249216
      )
      (unless (iszero (eq (get '__funid) 1878662314)) 
        (seq 
          (set 'x (calldataload 4))
          (seq 
            (set '_temp_521 (mul (get 'x) 2))
            (return (ref '_temp_521) 32)
          )
        )
      )
    )
    0
  )
)
```

Python上からスマートコントラクトのサンプルを動かしてみる

```bash: 
$ ipython
In [1]: from ethereum import tester as t
In [2]: s = t.state()
In [3]: c = s.abi_contract('mul2.se')
In [4]: c.double(42)
Out[4]: 84
In [5]: 
```

関数の定義を確認

```bash:
$ serpent mk_signature mul2.se
extern mul2.se: [double:[int256]:int256]
````

# サンプル動作の確認（その２）

もう一つ別のサンプルを準備する
こちらはキーバリュー値を管理する実装。NameCoinのようなドメインを管理するサービスはスマートコントラクトで実現できそうです。


```py:namecoin.se
def register(key, value):
    # Key not yet claimed
    if not self.storage[key]:
        self.storage[key] = value
        return(1)
    else:
        return(0)  # Key already claimed

def ask(key):
    return(self.storage[key])
```

Python上から動かしてみる

```bash: 
$ ipython
In [1]: from ethereum import tester as t

In [2]: s = t.state()

In [3]: c = s.abi_contract('namecoin.se')

In [4]: c.register(0x67656f726765, 45)
Out[4]: 1

In [5]: c.register(0x67656f726765, 20)
Out[5]: 0

In [6]: c.register(0x6861727279, 65)
Out[6]: 1

In [7]: c.ask(0x6861727279)
Out[7]: 65
```

きっかけ作りのための本当に触りだけになります。

こちらにもチュートリアル資料があるのでいろいろ試してみてください
http://mc2-umd.github.io/ethereumlab/docs/serpent_tutorial.pdf