les, light: LES/2 protocol version (#14970)
This PR implements the new LES protocol version extensions: * new and more efficient Merkle proofs reply format (when replying to a multiple Merkle proofs request, we just send a single set of trie nodes containing all necessary nodes) * BBT (BloomBitsTrie) works similarly to the existing CHT and contains the bloombits search data to speed up log searches * GetTxStatusMsg returns the inclusion position or the pending/queued/unknown state of a transaction referenced by hash * an optional signature of new block data (number/hash/td) can be included in AnnounceMsg to provide an option for "very light clients" (mobile/embedded devices) to skip expensive Ethash check and accept multiple signatures of somewhat trusted servers (still a lot better than trusting a single server completely and retrieving everything through RPC). The new client mode is not implemented in this PR, just the protocol extension.
This commit is contained in:
committed by
Felix Lange
parent
6d6a5a9337
commit
ca376ead88
@@ -18,24 +18,34 @@
|
||||
package les
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// Constants to match up protocol versions and messages
|
||||
const (
|
||||
lpv1 = 1
|
||||
lpv2 = 2
|
||||
)
|
||||
|
||||
// Supported versions of the les protocol (first is primary).
|
||||
var ProtocolVersions = []uint{lpv1}
|
||||
// Supported versions of the les protocol (first is primary)
|
||||
var (
|
||||
ClientProtocolVersions = []uint{lpv2, lpv1}
|
||||
ServerProtocolVersions = []uint{lpv2, lpv1}
|
||||
)
|
||||
|
||||
// Number of implemented message corresponding to different protocol versions.
|
||||
var ProtocolLengths = []uint64{15}
|
||||
var ProtocolLengths = map[uint]uint64{lpv1: 15, lpv2: 22}
|
||||
|
||||
const (
|
||||
NetworkId = 1
|
||||
@@ -53,13 +63,21 @@ const (
|
||||
BlockBodiesMsg = 0x05
|
||||
GetReceiptsMsg = 0x06
|
||||
ReceiptsMsg = 0x07
|
||||
GetProofsMsg = 0x08
|
||||
ProofsMsg = 0x09
|
||||
GetProofsV1Msg = 0x08
|
||||
ProofsV1Msg = 0x09
|
||||
GetCodeMsg = 0x0a
|
||||
CodeMsg = 0x0b
|
||||
SendTxMsg = 0x0c
|
||||
GetHeaderProofsMsg = 0x0d
|
||||
HeaderProofsMsg = 0x0e
|
||||
// Protocol messages belonging to LPV2
|
||||
GetProofsV2Msg = 0x0f
|
||||
ProofsV2Msg = 0x10
|
||||
GetHelperTrieProofsMsg = 0x11
|
||||
HelperTrieProofsMsg = 0x12
|
||||
SendTxV2Msg = 0x13
|
||||
GetTxStatusMsg = 0x14
|
||||
TxStatusMsg = 0x15
|
||||
)
|
||||
|
||||
type errCode int
|
||||
@@ -79,7 +97,7 @@ const (
|
||||
ErrUnexpectedResponse
|
||||
ErrInvalidResponse
|
||||
ErrTooManyTimeouts
|
||||
ErrHandshakeMissingKey
|
||||
ErrMissingKey
|
||||
)
|
||||
|
||||
func (e errCode) String() string {
|
||||
@@ -101,7 +119,13 @@ var errorToString = map[int]string{
|
||||
ErrUnexpectedResponse: "Unexpected response",
|
||||
ErrInvalidResponse: "Invalid response",
|
||||
ErrTooManyTimeouts: "Too many request timeouts",
|
||||
ErrHandshakeMissingKey: "Key missing from handshake message",
|
||||
ErrMissingKey: "Key missing from list",
|
||||
}
|
||||
|
||||
type announceBlock struct {
|
||||
Hash common.Hash // Hash of one particular block being announced
|
||||
Number uint64 // Number of one particular block being announced
|
||||
Td *big.Int // Total difficulty of one particular block being announced
|
||||
}
|
||||
|
||||
// announceData is the network packet for the block announcements.
|
||||
@@ -113,6 +137,32 @@ type announceData struct {
|
||||
Update keyValueList
|
||||
}
|
||||
|
||||
// sign adds a signature to the block announcement by the given privKey
|
||||
func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
|
||||
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
|
||||
sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey)
|
||||
a.Update = a.Update.add("sign", sig)
|
||||
}
|
||||
|
||||
// checkSignature verifies if the block announcement has a valid signature by the given pubKey
|
||||
func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error {
|
||||
var sig []byte
|
||||
if err := a.Update.decode().get("sign", &sig); err != nil {
|
||||
return err
|
||||
}
|
||||
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})
|
||||
recPubkey, err := secp256k1.RecoverPubkey(crypto.Keccak256(rlp), sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
|
||||
if bytes.Equal(pbytes, recPubkey) {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("Wrong signature")
|
||||
}
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
Hash common.Hash // Hash of one particular block being announced
|
||||
Number uint64 // Number of one particular block being announced
|
||||
|
Reference in New Issue
Block a user