This is the Python core library of the Ethereum project.
For the python based command line client see: https://github.com/ethereum/pyethapp
Installation:
sudo apt-get install libssl-dev build-essential automake pkg-config libtool libffi-dev libgmp-dev
git clone https://github.com/ethereum/pyethereum/
cd pyethereum
python setup.py install
Components
ethereum.pow.chain
Contains the Chain class, which can be used to manage a blockchain. Main methods are:
__init__(genesis=None, env=None, new_head_cb=None, reset_genesis=False, localtime=None)
- initializes with the given genesis.env
specifies the environment (including chain config and database),new_head_cb
is a callback called when a new head is added, andlocaltime
is what the chain assumes is the current timestamp. The genesis can be:- None - in which case it assumes
env
is given, and creates a Chain object with the data saved inenv.db
. Ifreset_genesis
is set, it re-initializes the chain. - A
State
object - A genesis declaration
- A state snapshot (
State.snapshot()
) - An allocation (ie. dict
{address: {balance: 1, nonce: 2, code: b'\x03\x04\x05', storage: {"0x06": "0x07"}}}
)
- None - in which case it assumes
add_block(block)
- adds a block to the chainprocess_time_queue(timestamp)
- tells the chain that the current time has increased to the new timestamp. The chain will then process any blocks that were unprocessed because they appeared too "early"get_blockhash_by_number(num)
- get the block hash of a block at the given block numberget_block(hash)
- gets the block with the given blockhashget_block_by_number(num)
- equivalent toget_block(get_blockhash_by_number(num))
get_parent(block)
- gets the parent of a blockget_children(block)
- gets the children of a blockhead
(property) - gets the block at the head of the chainstate
(property) - gets the state at the head of the chainmk_poststate_of_blockhash(hash)
- creates a state object after a given blockhas_block(block)
- is that block in the chain? Returns True/Falseget_chain(from, to)
- roughly equivalent to[get_block_by_number(i) for i in range(from, to)]
, though automatically stops if it reaches the head.from
can be elided to start from genesis,to
can be elided to go up to the head.get_tx_position(tx)
- if the transaction is in the chain, returns(blknum, index)
whereblknum
is the block number of the block that contains the transaction andindex
is its position in the block
ethereum.state
Contains the State class, which is used to manage a state. Main methods are:
__init__(root_hash, env, **kwargs)
- initializes a state with the given root hash, the given env (which includes a config and database) and the given auxiliary arguments. These include:txindex
- the transaction indexgas_used
- amount of gas usedgas_limit
- block gas limitblock_number
- block numberblock_coinbase
- block coinbase addressblock_difficulty
- block difficultytimestamp
- timestamplogs
- logs created so farreceipts
- receipts created so far (from previous transactions in the current block)bloom
- the bloom filtersuicides
- suicides (or selfdestructs, the newer more politically correct synonym)recent_uncles
- recent uncle blocks in the chainprev_headers
- previous block headersrefunds
- suicide/selfdestruct refund counter
Pyethereum follows a maximally state-centric model; the ONLY information needed to process a transaction or a block is located within the state itself, allowing the actual state transition logic to be a very clean apply_transaction(state, tx)
and apply_block(state, block)
.
get_balance
- gets the balance of an accountget_code
- gets the code of an accountget_storage_data(addr, k)
- gets the storage at the given key of the given address. Expects a key in numerical form (eg. b"cow" or "0x636f77" is represented as 6516599).to_snapshot(root_only=False, no_prevblocks=False)
- creates a snapshot for the current state. Ifroot_only
is set, only adds the state root, not the entire state. Ifno_prevblocks
is set, does not add previous headers and uncles. Setting either of those flags means that the same database would be required to recover from the snapshot.from_snapshot(snapshot, env)
(classmethod) - creates a state from the given snapshot with the givenenv
.ephemeral_clone()
- creates a clone of the state that you can work with without affecting the original
There are also many methods that modify the state, eg. set_code
, set_storage_data
, but it is generally recommended to avoid using these, and instead modify the state ONLY through apply_transaction
and apply_block
.
ethereum.meta
This file contains two functions:
apply_block(state, block)
- takes a state and processes a block onto that statemake_head_candidate(chain, txqueue=None, parent=None, timestamp, coinbase, extra_data, min_gasprice=0)
- creates a candidate block for the chain on top of the given parent block (default: head of the chain). Gets transactions from the giventxqueue
object with the givenmingasprice
(otherwise does not add transactions).timestamp
,coinbase
andextra_data
can be used to specify those parameters in the block; otherwise defaults are used
ethereum.messages
The main function that should be called from here is apply_transaction(state, tx)
.
ethereum.utils
Contains a bunch of utility functions, including:
Numerical and hex conversions
encode_int(i)
- converts an integer into big-endian binary representationzpad(data, length)
- pads the data up to the desired length by adding zero bytes on the leftencode_int32(i)
- equivalent tozpad(encode_int(i), 32)
but fasterbig_endian_to_int(d)
- converts binary data into an integerencode_hex(b)
- converts bytes to hexdecode_hex(h)
- converts hex to bytesint_to_addr(i)
- converts integer to addressis_numeric(i)
- returns True if the value is int or long, otherwise False
Cryptography
sha3(data)
- computes the SHA3 (or more precisely, keccak256) hashecrecover_to_pub(hash, v, r, s)
- recovers the public key that made the signature as a 64-byte binary blob ofencode_int32(x) + encode_int32(y)
. Hashing this and taking the last 20 bytes gives the address that signed a message.ecsign(hash, key)
- returns the v, r, s values of a signaturenormalize_key(key)
- converts a key from many formats into 32-byte binaryprivtoaddr(key)
- converts a key to an address
Addresses
normalize_address(addr)
- converts an address into 20-byte binary formcheck_checksum(addr)
- returns True if the address checksum passes, otherwise Falsechecksum_encode(addr)
- converts an address into hex form with a checksummk_contract_address(addr, nonce)
- creates the address of a contract created by the given address with the given nonce
Miscellaneous
denoms
- contains the denominations of ether, eg.denoms.finney = 10**15
,denoms.shannon = 10**9
,denoms.gwei = 10**9
ethereum.block
Contains the Block
and BlockHeader
classes. Generally recommended to avoid creating blocks and block headers directly, instead using mk_head_candidate
. The member variables are straightforward:
block.transactions
- transactions in a blockblock.uncles
- uncles in a blockblock.header
- header of a block
And in the header:
header.hash
- the hash (also the block hash)header.mining_hash
- the hash used for proof of work miningheader.to_dict()
- serializes into a human-readable dictheader.prevhash
- previous block hashheader.uncles_hash
- hash of the uncle listheader.coinbase
- coinbase (miner) addressheader.state_root
- root hash of the post-stateheader.tx_list_root
- hash of the transactions in the blockheader.receipts_root
- hash of the receipt trieheader.bloom
- bloom filterheader.difficulty
- block difficultyheader.number
- block numberheader.gas_limit
- gas limitheader.gas_used
- gas usedheader.timestamp
- timestampheader.extra_data
- block extra dataheader.mixhash
andheader.nonce
- Ethash proof of work values
ethereum.transactions
Contains the Transaction class, with the following methods and values:
__init__(nonce, gasprice, startgas, to, value, data, (v, r, s optional))
- constructorsign(key, network_id=None)
- signs the transaction with the given key, and with the given EIP155 chain ID (leaving as None will create a pre-EIP155 tx, be warned of replay attacks if you do this!)sender
- the sender address of the transactionnetwork_id
- the EIP155 chain ID of the transactionhash
- the hash of the transactionto_dict()
- serializes into a human-readable dictintrinsic_gas_used
- the amount of gas consumed by the transaction, including the cost of the tx datacreates
- if the transaction creates a contract, returns the contract addressnonce
,gasprice
,startgas
,to
,value
,data
,v
,r
,s
- parameters in the transaction
ethereum.tools.keys
Creates encrypted private key storages
decode_keystore_json(jsondata, password)
- returns the private key from an encrypted keystore object. NOTE: if you are loading from a file, the most convenient way to do this isimport json; key = decode_keystore_json(json.load(open('filename.json')), 'password')
make_keystore_json(key, pw, kdf='pbkdf2', cipher='aes-128-ctr')
- creates an encrypted keystore object for the key. Keepingkdf
andcipher
at their default values is recommended.
ethereum.abi
Most compilers for HLLs (solidity, serpent, viper, etc) on top of Ethereum have the option to output an ABI declaration for a program. This is a json object that looks something like this:
[{"name": "ecrecover(uint256,uint256,uint256,uint256)", "type": "function", "constant": false,
"inputs": [{"name": "h", "type": "uint256"}, {"name": "v", "type": "uint256"}, {"name": "r", "type": "uint256"}, {"name": "s", "type": "uint256"}],
"outputs": [{"name": "out", "type": "int256[]"}]},
{"name": "PubkeyTripleLogEvent(uint256,uint256,uint256)", "type": "event",
"inputs": [{"name": "x", "type": "uint256", "indexed": false}, {"name": "y", "type": "uint256", "indexed": false}, {"name": "z", "type": "uint256", "indexed": false}]}]
You can initialize an abi.ContractTranslator
object to encode and decode data for contracts as follows:
true, false = True, False
ct = abi.ContractTranslator(<json here>)
txdata = ct.encode('function_name', [arg1, arg2, arg3])
You can also call ct.decode_event([topic1, topic2...], logdata)
to decode a log.
RLP encoding and decoding
For any transaction or block, you can simply do:
import rlp
bindata = rlp.encode(<tx or block>)
To decode:
import rlp
from ethereum.transactions import Transaction
rlp.decode(blob, Transaction)
Or:
import rlp
from ethereum.blocks import Block
rlp.decode(blob, Block)
Consensus abstraction
The pyethereum codebase is designed to be maximally friendly for use across many different consensus algorithms. If you want to add a new consensus algo, you'll need to take the following steps:
- Add a directory alongside
pow
, and in it create achain.py
class that implements aChain
module. This may have a totally different fork choice rule for proof of work (GHOST, signature counting, Casper, etc). - Add an entry to
consensus_strategy.py
. You will need to implement:check_seal
- check that a block is correctly "sealed" (mined, signed, etc)validate_uncles(state, block)
- check that uncles are validinitialize(state, block)
- called inapply_block
before transactions are processedfinalize(state, block)
- called inapply_block
after transactions are processedget_uncle_candidates(chain, state)
- called inmk_head_candidate
to include uncles in a block
- Create a chain config with the
CONSENSUS_STRATEGY
set to whatever you named your new consensus strategy
Tester module
See https://github.com/ethereum/pyethereum/wiki/Using-pyethereum.tester
Tests
Run python3.6 -m pytest ethereum/tests/<filename>
for any .py file in that directory. Currently all tests are passing except for a few Metropolis-specific state tests and block tests.
To make your own state tests, use the tester module as follows:
from ethereum.tools import tester as t
import json
c = t.Chain()
x = c.contract(<code>, language=<language>)
pre = t.mk_state_test_prefill(c)
x.foo(<args>)
post = t.mk_state_test_postfill(c, pre)
open('output.json', 'w').write(json.dumps(post, indent=4))
To make a test filler file instead, do post = t.mk_state_test_postfill(c, pre, True)
.
License
See LICENSE