Serpentとは
- Serpent(サーペント:毒蛇)はPythonライクにEthereum(イーサリアム)のコントラクトを書くための言語
- Ethereum(イーサリアム)でコントラクトを実装する場合は、JavaScriptライクにコントラクトを書くことができるSolidityが圧倒的に流行っているのでSerpentは文献が少ない悲
- Ethereumの創設者であるVitalik Buterinはビットコインのライブラリ等(pybitcointools)をPythonで実装していたのでpython系を密かに応援していることを期待している
インストール(pyethereum)
- まずはpyethereumをインストールした(私の環境はMax OS X)
$ 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)
$ 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
サンプル動作の確認(その1)
以下の場所にあるサンプルの一部を動かしてみる
https://github.com/ethereum/wiki/wiki/Serpent
その他のサンプルは以下の場所に用意されている
https://github.com/ethereum/serpent/tree/master/examples
まずはserpentの簡単な実装を準備
mul2.se
def double(x):
return(x * 2)
コンパイル
$ serpent compile mul2.se
604380600b600039604e567c010000000000000000000000000000000000000000000000000000000060003504636ffa1caa81141560415760043560405260026040510260605260206060f35b505b6000f3
コンパイル(pretty_compile)
$ 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?)に変換
$ 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上からスマートコントラクトのサンプルを動かしてみる
$ 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]:
関数の定義を確認
$ serpent mk_signature mul2.se
extern mul2.se: [double:[int256]:int256]
サンプル動作の確認(その2)
もう一つ別のサンプルを準備する
こちらはキーバリュー値を管理する実装。NameCoinのようなドメインを管理するサービスはスマートコントラクトで実現できそうです。
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上から動かしてみる
$ 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