Light Ethereum Subprotocol (LES)

Felföldi Zsolt edited this page Oct 16, 2017 · 42 revisions

The Light Ethereum Subprotocol (LES) is the protocol used by "light" clients, which only download block headers as they appear and fetch other parts of the blockchain on-demand. They provide full functionality in terms of safely accessing the blockchain, but do not mine and therefore do not take part in the consensus process. Full and archive nodes can also support the LES protocol besides ETH in order to be able to serve light nodes. It has been decided to create a separate sub-protocol in order to avoid interference with the consensus-critical ETH network and make it easier to update during the development phase. Some of the LES protocol messages are similar to the "new sync model" (ETH62/63) of the Ethereum Wire Protocol, with the addition of a few new fields (see below).

Request ID

Every on-demand request message contains a reqID field, which is simply returned by the server in the corresponding reply message. This helps matching replies for requests on the client side so that each reply doesn't need to be matched against each pending request.

Client Side Flow Control

Every reply message contains a BV (Buffer Value) flow control feedback field, see Client Side Flow Control

Messages of the LES/1 protocol version (LPV1)

Handshake

Status [+0x00, [key_0, value_0], [key_1, value_1], ...] Inform a peer of the sender's current LES state. This message should be sent after the initial handshake and prior to any LES related messages. The following keys should be present (except the optional ones) in order to be accepted by a LES/1 node: (value types are noted after the key string)

  • "protocolVersion" P: is 1 for the LPV1 protocol version.
  • "networkId" P: should be 0 for testnet, 1 for mainnet.
  • "headTd" P: Total Difficulty of the best chain. Integer, as found in block header.
  • "headHash" B_32: the hash of the best (i.e. highest TD) known block.
  • "headNum" P: the number of the best (i.e. highest TD) known block.
  • "genesisHash" B_32: the hash of the Genesis block.
  • "serveHeaders" (optional, no value): present if the peer can serve header chain downloads.
  • "serveChainSince" P (optional): present if the peer can serve Body/Receipts ODR requests starting from the given block number.
  • "serveStateSince" P (optional): present if the peer can serve Proof/Code ODR requests starting from the given block number.
  • "txRelay" (optional, no value): present if the peer can relay transactions to the ETH network.
  • "flowControl/BL", "flowControl/MRC", "flowControl/MRR": see Client Side Flow Control

Unknown keys should be ignored by both sides. This allows announcing additional capabilities while staying compatible with the LES/1 protocol version.

Header synchronisation

Announce [+0x01, headHash: B_32, headNumber: P, headTd: P, reorgDepth: P, [key_0, value_0], [key_1, value_1], ...] Announce a new chain head and optionally also a change to some of the values announced at handshake. A restrictive change of server capabilities (for example, an increase of "serveStateSince" due to state pruning) should be announced at least 10 seconds prior to actually restricting those capabilities in order to avoid asynchronous problems. Changes to unknown keys should be ignored. Changes to known keys that make no sense lead to disconnection. Announcing a head with a lower or equal TD than previously announced or a head that the sending node later refuses to honour with a proceeding GetBlockHeaders message (with number and TD also matching) is considered Bad Form, and may lead to disconnection or reduce the reputation of the sending node. The field reorgDepth contains the number of blocks to be rolled back from the last head announced by the same node in order to find the last common ancestor of the last and current heaviest chain. Adding this field helps the client to minimize the number of requests and the amount of bandwidth required to fetch new headers.

GetBlockHeaders [+0x02, reqID: P, [block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ]] Require peer to return a BlockHeaders message. Reply must contain a number of block headers, of rising number when reverse is 0, falling when 1, skip blocks apart, beginning at block block (denoted by either number or hash) in the canonical chain, and with at most maxHeaders items.

BlockHeaders [+0x03, reqID: P, BV: P, [blockHeader_0, blockHeader_1, ...]] Reply to GetBlockHeaders. The items in the list (following the message ID) are block headers in the format described in the main Ethereum specification, previously asked for in a GetBlockHeaders message. This may validly contain no block headers if no block headers were able to be returned for the GetBlockHeaders query.

On-demand data retrieval

GetBlockBodies [+0x04, reqID: P, [hash_0: B_32, hash_1: B_32, ...]] Require peer to return a BlockBodies message. Specify the set of blocks that we're interested in with the hashes.

BlockBodies [+0x05, reqID: P, BV: P, [ [transactions_0, uncles_0] , ...]] Reply to GetBlockBodies. The items in the list (following the message ID) are some of the blocks, minus the header, in the format described in the main Ethereum specification, previously asked for in a GetBlockBodies message.

GetReceipts [+0x06, reqID: P, [hash_0: B_32, hash_1: B_32, ...]] Require peer to return a Receipts message.

Receipts [+0x07, reqID: P, BV: P, [ [receipt_0, receipt_1, ...], ...]] Provide a set of receipts which correspond to the block hashes previously asked in GetReceipts.

GetProofs [+0x08, reqID: P, [ [blockhash: B_32, key: B_32, key2: B_32, fromLevel: P], ...]] Require peer to return a Proofs message, containing one or more Merkle proofs, each proving the value of index key from the state trie of the given block (if key2 is empty), or the storage value of index key2 from the storage trie referenced in the account at key. If fromLevel is greater than zero, the given number of trie nodes closest to the root can be omitted from the proof.

Proofs [+0x09, reqID: P, BV: P, [ [node_1, node_2, ...], ...]] Return a set of Merkle proofs, each consisting of a set of nodes that must be processed in order to access the trie entry value (or prove the absence of an entry) requested in GetProofs

GetContractCodes [+0x0a, reqID: P, [ [blockhash: B_32, key: B_32], ...]] Require peer to return a ContractCodes message.

ContractCodes [+0x0b, reqID: P, BV: P, [value_0: B, value_1: B, ...]] Provide a set of contract codes which correspond to the block hashes and account keys previously asked in GetContractCodes.

GetHeaderProofs [+0x0d, reqID: P, [ [chtNumber: P, blockNumber: P, fromLevel: P], ...]] Require peer to return a HeaderProofs message, containing one or more canonical block headers (of block number blockNumber) and corresponding Merkle proofs of the CHT (Canonical Hash Trie) identified by chtNumber. If fromLevel is greater than zero, the given number of trie nodes closest to the root can be omitted from the proof.

HeaderProofs [+0x0e, reqID: P, BV: P, [ [blockHeader, [node_1, node_2...]], ...]] Return a set of structures, each containing a block header and a Merkle proof proving the header hash and belonging TD against a given CHT requested in GetHeaderProofs

Transaction relaying

SendTx [+0x0c, txdata_1, txdata_2, ...] Require peer to add a set of transactions into its transaction pool and relay them to the ETH network.

Messages of the LES/2 protocol version (LPV2)

Handshake

Status The message format identical to LES/1 with an additional key:

  • "announceType" P: set by clients, this field affects the Announce messages of the server. Allowed values are: none (0): no Announce messages are sent. simple (1, default): Announce messages are identical to LES/1 messages. signed (2): there is a "sign" key in the key/value list of Announce messages. The belonging value is a signature of an RLP encoded [headHash: B_32, headNumber: P, headTd: P] structure by the server's node key.

On-demand data retrieval

GetProofsV2 [+0x0f, reqID: P, [ [blockhash: B_32, key: B_32, key2: B_32, fromLevel: P], ...]] Require peer to return a ProofsV2 message, containing a single (and smallest possible) set of trie nodes that proves for each request the value of index key from the state trie of the given block (if key2 is empty), or the storage value of index key2 from the storage trie referenced in the account at key. If fromLevel is greater than zero, the given number of trie nodes closest to the root can be omitted from the proof.

ProofsV2 [+0x10, reqID: P, BV: P, [node_1, node_2, ...]] Return the smallest set of trie nodes required to access the trie entry value (or prove the absence of an entry) requested in GetProofsV2. This set will be called a proof set.

GetHelperTrieProofs [+0x11, reqID: P, [ [subType: P, sectionIdx: P, key: B, fromLevel: P, auxReq: P], ...]] Require peer to return a HelperTrieProofs message, containing a proof set and optional auxiliary data for each request.

Note: this request is a generalization of the LES/1 GetHeaderProofs message. It retrieves Merkle proofs from different types of "helper tries" which are generated for every fixed-length section of the canonical chain. subType identifies the helper trie that is being requested for the section marked by sectionIdx. key and fromLevel are interpreted like in case of proof requests.

If auxReq is greater than zero then auxiliary data is requested too. If auxReq is 1 then the root hash of the specified trie (according to the server) is returned and no trie nodes are added to the proof set. This special request will be required for trustless validation of helper tries. The interpretation of auxReq values greater than 1 is subject to subType.

The following subType values are allowed in LES/2:

  • CHT (0): request a key from the Canonical Hash Trie. If auxReq is 2 then the belonging header is returned as auxData. key is the block number encoded as an 8-byte big endian. Note that the section size for CHTs has been raised to 32k instead of 4k blocks so for example a sectionIdx of 100 equals a chtNumber of 807 in case of the old GetHeaderProofs message.
  • BloomBits (1): request a key from the BloomBits Trie. In this trie key is 10 bytes long, it consists of the bloom bit index encoded as a 2-byte big endian, followed by the section index encoded as an 8-byte big endian. The returned value is the corresponding compressed bloom bit vector.

HelperTrieProofs [+0x12, reqID: P, BV: P, [ [node_1, node_2...], [auxData_0, auxData_1, ...]] Return a proof set and a set of auxData requested in GetHelperTrieProofs. The length of the auxData list equals the number of requests with a non-zero auxReq.

Transaction relaying and status retrieval

SendTxV2 [+0x13, reqID: P, [txdata_1, txdata_2, ...]] Require peer to add a set of transactions into its transaction pool and relay them to the ETH network, then return a TxStatus message containing the status of the sent transactions.

GetTxStatus [+0x14, reqID: P, [txHash_1, txHash_2, ...]] Require peer to return a TxStatus message containing the status of the referenced transactions.

TxStatus [+0x15, reqID: P, BV: P, [ [status: P, data: B], ...]] Return the current status of the sent/queried transactions. Possible status values are:

  • Unknown (0): transaction is unknown
  • Queued (1): transaction is queued (not processable yet)
  • Pending (2): transaction is pending (processable)
  • Included (3): transaction is already included in the canonical chain. data contains an RLP-encoded [blockHash: B_32, blockNumber: P, txIndex: P] structure
  • Error (4): transaction sending failed. data contains a text error message
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.