Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit 63f7b44

Browse files
committed
Aah, I get it
1 parent 5617231 commit 63f7b44

File tree

2 files changed

+242
-1
lines changed

2 files changed

+242
-1
lines changed

README.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
This is the Python core library of the Ethereum project.
2+
3+
For the python based command line client see:
4+
https://github.com/ethereum/pyethapp
5+
6+
## Installation:
7+
8+
``git clone https://github.com/ethereum/pyethereum/``
9+
10+
``cd pyethereum``
11+
12+
``python setup.py install``
13+
14+
15+
## Components
16+
17+
### ethereum.pow.chain
18+
19+
Contains the Chain class, which can be used to manage a blockchain. Main methods are:
20+
21+
* `__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, and `localtime` is what the chain assumes is the current timestamp. The genesis can be:
22+
* None - in which case it assumes `env` is given, and creates a Chain object with the data saved in `env.db`. If `reset_genesis` is set, it re-initializes the chain.
23+
* A `State` object
24+
* A genesis declaration
25+
* A state snapshot (`State.snapshot()`)
26+
* An allocation (ie. dict `{address: {balance: 1, nonce: 2, code: b'\x03\x04\x05', storage: {"0x06": "0x07"}}}`)
27+
* `add_block(block)` - adds a block to the chain
28+
* `process_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"
29+
* `get_blockhash_by_number(num)` - get the block hash of a block at the given block number
30+
* `get_block(hash)` - gets the block with the given blockhash
31+
* `get_block_by_number(num)` - equivalent to `get_block(get_blockhash_by_number(num))`
32+
* `get_parent(block)` - gets the parent of a block
33+
* `get_children(block)` - gets the children of a block
34+
* `head` (property) - gets the block at the head of the chain
35+
* `state` (property) - gets the state at the head of the chain
36+
* `mk_poststate_of_blockhash(hash)` - creates a state object after a given block
37+
* `has_block(block)` - is that block in the chain? Returns True/False
38+
* `get_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.
39+
* `get_tx_position(tx)` - if the transaction is in the chain, returns `(blknum, index)` where `blknum` is the block number of the block that contains the transaction and `index` is its position in the block
40+
41+
### ethereum.state
42+
43+
Contains the State class, which is used to manage a state. Main methods are:
44+
45+
* `__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:
46+
* `txindex` - the transaction index
47+
* `gas_used` - amount of gas used
48+
* `gas_limit` - block gas limit
49+
* `block_number` - block number
50+
* `block_coinbase` - block coinbase address
51+
* `block_difficulty` - block difficulty
52+
* `timestamp` - timestamp
53+
* `logs` - logs created so far
54+
* `receipts` - receipts created so far (from previous transactions in the current block)
55+
* `bloom` - the bloom filter
56+
* `suicides` - suicides (or selfdestructs, the newer more politically correct synonym)
57+
* `recent_uncles` - recent uncle blocks in the chain
58+
* `prev_headers` - previous block headers
59+
* `refunds` - suicide/selfdestruct refund counter
60+
61+
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)`.
62+
63+
* `get_balance`- gets the balance of an account
64+
* `get_code` - gets the code of an account
65+
* `get_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).
66+
* `to_snapshot(root_only=False, no_prevblocks=False)` - creates a snapshot for the current state. If `root_only` is set, only adds the state root, not the entire state. If `no_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.
67+
* `from_snapshot(snapshot, env)` (classmethod) - creates a state from the given snapshot with the given `env`.
68+
* `ephemeral_clone()` - creates a clone of the state that you can work with without affecting the original
69+
70+
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`.
71+
72+
### ethereum.meta
73+
74+
This file contains two functions:
75+
76+
* `apply_block(state, block)` - takes a state and processes a block onto that state
77+
* `make_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 given `txqueue` object with the given `mingasprice` (otherwise does not add transactions). `timestamp`, `coinbase` and `extra_data` can be used to specify those parameters in the block; otherwise defaults are used
78+
79+
### ethereum.messages
80+
81+
The main function that should be called from here is `apply_transaction(state, tx)`.
82+
83+
### ethereum.utils
84+
85+
Contains a bunch of utility functions, including:
86+
87+
#### Numerical and hex conversions
88+
89+
* `encode_int(i)` - converts an integer into big-endian binary representation
90+
* `zpad(data, length)` - pads the data up to the desired length by adding zero bytes on the left
91+
* `encode_int32(i)` - equivalent to `zpad(encode_int(i), 32)` but faster
92+
* `big_endian_to_int(d)` - converts binary data into an integer
93+
* `encode_hex(b)` - converts bytes to hex
94+
* `decode_hex(h)` - converts hex to bytes
95+
* `int_to_addr(i)` - converts integer to address
96+
* `is_numeric(i)` - returns True if the value is int or long, otherwise False
97+
98+
#### Cryptography
99+
100+
* `sha3(data)` - computes the SHA3 (or more precisely, keccak256) hash
101+
* `ecrecover_to_pub(hash, v, r, s)` - recovers the public key that made the signature as a 64-byte binary blob of `encode_int32(x) + encode_int32(y)`. Hashing this and taking the last 20 bytes gives the _address_ that signed a message.
102+
* `ecsign(hash, key)` - returns the v, r, s values of a signature
103+
* `normalize_key(key)` - converts a key from many formats into 32-byte binary
104+
* `privtoaddr(key)` - converts a key to an address
105+
106+
#### Addresses
107+
108+
* `normalize_address(addr)` - converts an address into 20-byte binary form
109+
* `check_checksum(addr)` - returns True if the address checksum passes, otherwise False
110+
* `checksum_encode(addr)` - converts an address into hex form with a checksum
111+
* `mk_contract_address(addr, nonce)` - creates the address of a contract created by the given address with the given nonce
112+
113+
#### Miscellaneous
114+
115+
* `denoms` - contains the denominations of ether, eg. `denoms.finney = 10**15`, `denoms.shannon = 10**9`, `denoms.gwei = 10**9`
116+
117+
### ethereum.block
118+
119+
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:
120+
121+
* `block.transactions` - transactions in a block
122+
* `block.uncles` - uncles in a block
123+
* `block.header` - header of a block
124+
125+
And in the header:
126+
127+
* `header.hash` - the hash (also the block hash)
128+
* `header.mining_hash` - the hash used for proof of work mining
129+
* `header.to_dict()` - serializes into a human-readable dict
130+
* `header.prevhash` - previous block hash
131+
* `header.uncles_hash` - hash of the uncle list
132+
* `header.coinbase` - coinbase (miner) address
133+
* `header.state_root` - root hash of the post-state
134+
* `header.tx_list_root` - hash of the transactions in the block
135+
* `header.receipts_root` - hash of the receipt trie
136+
* `header.bloom` - bloom filter
137+
* `header.difficulty` - block difficulty
138+
* `header.number` - block number
139+
* `header.gas_limit` - gas limit
140+
* `header.gas_used` - gas used
141+
* `header.timestamp` - timestamp
142+
* `header.extra_data` - block extra data
143+
* `header.mixhash` and `header.nonce` - Ethash proof of work values
144+
145+
### ethereum.transactions
146+
147+
Contains the Transaction class, with the following methods and values:
148+
149+
* `__init__(nonce, gasprice, startgas, to, value, data, (v, r, s optional))` - constructor
150+
* `sign(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!)
151+
* `sender` - the sender address of the transaction
152+
* `network_id` - the EIP155 chain ID of the transaction
153+
* `hash` - the hash of the transaction
154+
* `to_dict()` - serializes into a human-readable dict
155+
* `intrinsic_gas_used` - the amount of gas consumed by the transaction, including the cost of the tx data
156+
* `creates` - if the transaction creates a contract, returns the contract address
157+
* `nonce`, `gasprice`, `startgas`, `to`, `value`, `data`, `v`, `r`, `s` - parameters in the transaction
158+
159+
### ethereum.tools.keys
160+
161+
Creates encrypted private key storaes
162+
163+
* `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 is `import json; key = decode_keystore_json(json.load(open('filename.json')), 'password')`
164+
* `make_keystore_json(key, pw, kdf='pbkdf2', cipher='aes-128-ctr')` - creates an encrypted keystore object for the key. Keeping `kdf` and `cipher` at their default values is recommended.
165+
166+
### ethereum.abi
167+
168+
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:
169+
170+
[{"name": "ecrecover(uint256,uint256,uint256,uint256)", "type": "function", "constant": false,
171+
"inputs": [{"name": "h", "type": "uint256"}, {"name": "v", "type": "uint256"}, {"name": "r", "type": "uint256"}, {"name": "s", "type": "uint256"}],
172+
"outputs": [{"name": "out", "type": "int256[]"}]},
173+
{"name": "PubkeyTripleLogEvent(uint256,uint256,uint256)", "type": "event",
174+
"inputs": [{"name": "x", "type": "uint256", "indexed": false}, {"name": "y", "type": "uint256", "indexed": false}, {"name": "z", "type": "uint256", "indexed": false}]}]
175+
176+
You can initialize an `abi.ContractTranslator` object to encode and decode data for contracts as follows:
177+
178+
true, false = True, False
179+
ct = abi.ContractTranslator(<json here>)
180+
txdata = ct.encode('function_name', [arg1, arg2, arg3])
181+
182+
You can also call `ct.decode_event([topic1, topic2...], logdata)` to decode a log.
183+
184+
### RLP encoding and decoding
185+
186+
For any transaction or block, you can simply do:
187+
188+
import rlp
189+
bindata = rlp.encode(<tx or block>)
190+
191+
To decode:
192+
193+
import rlp
194+
from ethereum.transactions import Transaction
195+
rlp.decode(blob, Transaction)
196+
197+
Or:
198+
199+
import rlp
200+
from ethereum.blocks import Block
201+
rlp.decode(blob, Block)
202+
203+
### Consensus abstraction
204+
205+
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:
206+
207+
* Add a directory alongside `pow`, and in it create a `chain.py` class that implements a `Chain` module. This may have a totally different fork choice rule for proof of work (GHOST, signature counting, Casper, etc).
208+
* Add an entry to `consensus_strategy.py`. You will need to implement:
209+
* `check_seal` - check that a block is correctly "sealed" (mined, signed, etc)
210+
* `validate_uncles(state, block)` - check that uncles are valid
211+
* `initialize(state, block)` - called in `apply_block` before transactions are processed
212+
* `finalize(state, block)` - called in `apply_block` after transactions are processed
213+
* `get_uncle_candidates(chain, state)` - called in `mk_head_candidate` to include uncles in a block
214+
* Create a chain config with the `CONSENSUS_STRATEGY` set to whatever you named your new consensus strategy
215+
216+
## Tester module
217+
218+
See https://github.com/ethereum/pyethereum/wiki/Using-pyethereum.tester
219+
220+
## Tests
221+
222+
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.
223+
224+
To make your own state tests, use the tester module as follows:
225+
226+
```
227+
from ethereum.tools import tester as t
228+
import json
229+
c = t.Chain()
230+
x = c.contract(<code>, language=<language>)
231+
pre = t.mk_state_test_prefill(c)
232+
x.foo(<args>)
233+
post = t.mk_state_test_postfill(c, pre)
234+
open('output.json', 'w').write(json.dumps(post, indent=4))
235+
```
236+
237+
To make a test filler file instead, do `post = t.mk_state_test_postfill(c, pre, True)`.
238+
239+
## Licence
240+
241+
See LICENCE

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from setuptools import setup, find_packages
22

33

4-
with open('README.md') as readme_file:
4+
with open('README.rst') as readme_file:
55
readme = readme_file.read()
66

77
# requirements

0 commit comments

Comments
 (0)