-
Notifications
You must be signed in to change notification settings - Fork 604
Code Walkthrough
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.
- 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
Wait for data on the socket: https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L208
add the (partial) message to the MultiplexedSession: https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L223
try to decode packets (objects representing the equivalent to to a rpc cmd): https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/muxsession.py#L66
decode if there is enough data in the buffer https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/multiplexer.py#L520 https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/multiplexer.py#L426
using the cipher https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/muxsession.py#L17
which we have in the RLPx session https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/rlpxcipher.py#L41
decoded packets are put in a queue which are processed by a greenlet https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L197
which was spawned by https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L203
the Peer instance which is another greenlet https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L22
the protocol for handling the packet is resolved https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L164
and given the packet https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/peer.py#L174 https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/protocol.py#L160
in our case we assume the packet is for the "eth" protocol https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_protocol.py#L15
The ETHProtocol instance was linked to the ChainService instance on creation, which registered callbacks https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L334
which are called https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/protocol.py#L68
after the Packet.cmd_id is resolved to a handling command class https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/protocol.py#L160 https://github.com/ethereum/pydevp2p/blob/6577016a6f50ce220e20f66c2c8c1eb6dc271b9c/devp2p/protocol.py#L44
in our case eth_protocol.NewBlock: https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_protocol.py#L143
which decodes the payload: https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_protocol.py#L157
the registered callback function is called and handles the message: https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L461
new blocks are handled by the synchronizer which knows the state of the synchronization: https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L283
if the block is unknown https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L294
and pow is valid https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L299
and chain difficulty sufficient https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L304
and we have a parent for the block https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L304
the block is added to a queue https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/synchronizer.py#L304 https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L202
which is processed by a greenlet https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L207
which pop blocks from the queue and tries to add them to the chain: https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L228
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 https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L252 https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_protocol.py#L220
blocks.Block and blocks.BlockHeader are subclasses of rlp.Serializable https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L378 https://github.com/ethereum/pyrlp/blob/45160b64cc13c2c4b688965aec5028bef2e67f94/rlp/sedes/lists.py#L89
on blocks.Block.init https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L404
the block is checked for consistency https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L436
the transactions are executed to update the state https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L481 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L119
transactions are validated https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L86
sender account nonce increased https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L124
gas is checked and handled https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L127
a message to the account and call data are prepared https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L132
the message is applied https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L137 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L221
value is transfered https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L237
the vm invoked https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L245 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/vm.py#L151
read / writes to the state and limited access to the external environment is provided by the VmExt class https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/vm.py#L151 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L185
writes (state updates) are cached and journaled, so they can be reverted if the tx is invalid https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L195 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L975 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L754
if the message could successfully be applied, the transaction is valid https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L157
the state is committed https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L174 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L1002
the transaction added to the list of txs of the block: https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/processblock.py#L180
after all transactions are applied, the block is finalized: https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L483 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L1158
the block with its resulting state is verified https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L497 https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L266
FIXME, where do we validate uncles? https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/blocks.py#L642
If everything worked, we are back in ChainService and add the block to the chain https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L279 https://github.com/ethereum/pyethapp/blob/e4ce60854785ffec4fd2b9490fd58a015287c7c0/pyethapp/eth_service.py#L281 https://github.com/ethereum/pyethereum/blob/efb08554ee95aa18b08d8f5d21d76097631d2c4a/ethereum/chain.py#L274