[PYTHON] Write Ethereum contract code using Serpent

What is Serpent

Installation (pyethereum)

python


$ 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

Installation (serpent)

python


$ 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

Confirmation of sample operation (1)

Try moving some of the samples in the following locations https://github.com/ethereum/wiki/wiki/Serpent

Other samples are available at the following locations https://github.com/ethereum/serpent/tree/master/examples

First, prepare a simple implementation of serpent

mul2.se


def double(x):
    return(x * 2)

compile

python


$ serpent compile mul2.se
604380600b600039604e567c010000000000000000000000000000000000000000000000000000000060003504636ffa1caa81141560415760043560405260026040510260605260206060f35b505b6000f3

Compile (pretty_compile)

python


$ 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]

Convert to LLL format (LISP?)

python


$ 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
  )
)

Try running a smart contract sample from 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]: 

Check the function definition

python


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

Confirmation of sample operation (Part 2)

Prepare another sample This is an implementation that manages key value values. Services that manage domains like NameCoin are likely to be realized with smart contracts.

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])

Try running it from 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

It's really just a touch to create a chance.

There are tutorial materials here as well, so please try various things. http://mc2-umd.github.io/ethereumlab/docs/serpent_tutorial.pdf

Recommended Posts

Write Ethereum contract code using Serpent
Write test-driven FizzBuzz code using Python doctest.
Write python-like code
Write Python-like code (dictionary)
Write FizzBuzz without using "="
Write standard input in code
Write Spigot in VS Code
Write Python code that applies type information at runtime using pydantic