LoginSignup
7
3

More than 5 years have passed since last update.

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

Posted at

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

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3