Skip to content
This repository has been archived by the owner on Aug 8, 2018. It is now read-only.

Code Walkthrough

Roman edited this page Mar 29, 2018 · 9 revisions

Following a block from the network socket to the hard drive

Note: All links to the code are based on a fixed revision, so we can link line numbers. Code might have changed by now, nonetheless use these revisions when doing updates to this document.

Preconditions

  • the app was configured and started
  • all services registered
  • the discovery protocol discovered some nodes
  • the peermanager successfully connected a node
  • established an encrypted multiplexed session
  • and created a ETHProtocol instance for this peer
  • we are waiting for ingress data in the peer connection

Receiving and decoding network data

Wait for data on the socket: devp2p/peer.py#L208

add the (partial) message to the MultiplexedSession: devp2p/peer.py#L223

try to decode packets (objects representing the equivalent to a rpc cmd): devp2p/muxsession.py#L66

decode if there is enough data in the buffer devp2p/multiplexer.py#L520 devp2p/multiplexer.py#L426

decrypt devp2p/multiplexer.py#L442

using the cipher devp2p/muxsession.py#L17

which we have in the RLPx session devp2p/rlpxcipher.py#L41

decoded packets are put in a queue which are processed by a greenlet devp2p/peer.py#L197

which was spawned by devp2p/peer.py#L203

the Peer instance which is another greenlet devp2p/peer.py#L22

the protocol for handling the packet is resolved devp2p/peer.py#L164

and given the packet devp2p/peer.py#L174 devp2p/protocol.py#L160

in our case we assume the packet is for the "eth" protocol pyethapp/eth_protocol.py#L15

Handling the message

The ETHProtocol instance was linked to the ChainService instance on creation, which registered callbacks pyethapp/eth_service.py#L334

which are called devp2p/protocol.py#L68

after the Packet.cmd_id is resolved to a handling command class devp2p/protocol.py#L160 devp2p/protocol.py#L44

in our case eth_protocol.NewBlock: pyethapp/eth_protocol.py#L143

which decodes the payload: pyethapp/eth_protocol.py#L157

the registered callback function is called and handles the message: pyethapp/eth_service.py#L461

new blocks are handled by the synchronizer which knows the state of the synchronization: pyethapp/synchronizer.py#L283

if the block is unknown pyethapp/synchronizer.py#L294

and pow is valid pyethapp/synchronizer.py#L299

and chain difficulty sufficient pyethapp/synchronizer.py#L304

and we have a parent for the block pyethapp/synchronizer.py#L304

the block is added to a queue pyethapp/synchronizer.py#L304 pyethapp/eth_service.py#L202

which is processed by a greenlet pyethapp/eth_service.py#L207

which pop blocks from the queue and tries to add them to the chain: pyethapp/eth_service.py#L228

Entering the Blockchain

so far we had a transient block (t_block) which was not yet connected to the database, i.e. it could not access its ancestors or access state.

it is now deserialized to a block.Block pyethapp/eth_service.py#L252 pyethapp/eth_protocol.py#L220

blocks.Block and blocks.BlockHeader are subclasses of rlp.Serializable ethereum/blocks.py#L378 sedes/lists.py#L89

on blocks.Block init ethereum/blocks.py#L404

the block is checked for consistency ethereum/blocks.py#L436

Entering the VM

the transactions are executed to update the state ethereum/blocks.py#L481 ethereum/processblock.py#L119

transactions are validated ethereum/processblock.py#L86

sender account nonce increased ethereum/processblock.py#L124

gas is checked and handled ethereum/processblock.py#L127

a message to the account and call data are prepared ethereum/processblock.py#L132

the message is applied ethereum/processblock.py#L137 ethereum/processblock.py#L221

value is transfered ethereum/processblock.py#L237

the vm invoked ethereum/processblock.py#L245 ethereum/vm.py#L151

read / writes to the state and limited access to the external environment is provided by the VmExt class ethereum/vm.py#L151 ethereum/processblock.py#L185

writes (state updates) are cached and journaled, so they can be reverted if the tx is invalid ethereum/processblock.py#L195 ethereum/blocks.py#L975 ethereum/blocks.py#L754

if the message could successfully be applied, the transaction is valid ethereum/processblock.py#L157

the state is committed ethereum/processblock.py#L174 ethereum/blocks.py#L1002

the transaction added to the list of txs of the block: ethereum/processblock.py#L180

after all transactions are applied, the block is finalized: ethereum/blocks.py#L483 ethereum/blocks.py#L1158

the block with its resulting state is verified ethereum/blocks.py#L497 pyethapp/eth_service.py#L266

Adding the block to the chain

If everything worked, we are back in ChainService and add the block to the chain pyethapp/eth_service.py#L279 pyethapp/eth_service.py#L281 ethereum/chain.py#L274

here we validate the uncles: ethereum/chain.py#L282 ethereum/blocks.py#L642

do another verification: ethereum/chain.py#L296

update the index: ethereum/chain.py#L307 ethereum/chain.py#L35 ethereum/chain.py#L86 ethereum/chain.py#L67

store the block: ethereum/chain.py#L308 ethereum/chain.py#L265 ethereum/refcount_db.py#L154 ethereum/refcount_db.py#L23 ethereum/refcount_db.py#L32 pyethapp/leveldb_service.py#L74

update the head of the chain: ethereum/chain.py#L310 ethereum/chain.py#L313 ethereum/chain.py#L153

update the head candidate (i.e. the block we are mining on and are adding new txs to): ethereum/chain.py#L193 ethereum/chain.py#L197 ethereum/chain.py#L222

finally commit: ethereum/chain.py#L320 ethereum/refcount_db.py#L101 pyethapp/leveldb_service.py#L78

Et, voilà! The block made it to the harddrive :)

Next up: Code Walkthrough - from the JSONRPC socket through the blockchain to the network.