199 lines
6.1 KiB
Go
199 lines
6.1 KiB
Go
|
// Copyright 2015 The go-ethereum Authors
|
||
|
// This file is part of the go-ethereum library.
|
||
|
//
|
||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU Lesser General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU Lesser General Public License
|
||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
// Package les implements the Light Ethereum Subprotocol.
|
||
|
package les
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"math/big"
|
||
|
|
||
|
"github.com/ethereum/go-ethereum/common"
|
||
|
"github.com/ethereum/go-ethereum/core/types"
|
||
|
"github.com/ethereum/go-ethereum/rlp"
|
||
|
)
|
||
|
|
||
|
// Constants to match up protocol versions and messages
|
||
|
const (
|
||
|
lpv1 = 1
|
||
|
)
|
||
|
|
||
|
// Supported versions of the les protocol (first is primary).
|
||
|
var ProtocolVersions = []uint{lpv1}
|
||
|
|
||
|
// Number of implemented message corresponding to different protocol versions.
|
||
|
var ProtocolLengths = []uint64{15}
|
||
|
|
||
|
const (
|
||
|
NetworkId = 1
|
||
|
ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message
|
||
|
)
|
||
|
|
||
|
// les protocol message codes
|
||
|
const (
|
||
|
// Protocol messages belonging to LPV1
|
||
|
StatusMsg = 0x00
|
||
|
AnnounceMsg = 0x01
|
||
|
GetBlockHeadersMsg = 0x02
|
||
|
BlockHeadersMsg = 0x03
|
||
|
GetBlockBodiesMsg = 0x04
|
||
|
BlockBodiesMsg = 0x05
|
||
|
GetReceiptsMsg = 0x06
|
||
|
ReceiptsMsg = 0x07
|
||
|
GetProofsMsg = 0x08
|
||
|
ProofsMsg = 0x09
|
||
|
GetCodeMsg = 0x0a
|
||
|
CodeMsg = 0x0b
|
||
|
SendTxMsg = 0x0c
|
||
|
GetHeaderProofsMsg = 0x0d
|
||
|
HeaderProofsMsg = 0x0e
|
||
|
)
|
||
|
|
||
|
type errCode int
|
||
|
|
||
|
const (
|
||
|
ErrMsgTooLarge = iota
|
||
|
ErrDecode
|
||
|
ErrInvalidMsgCode
|
||
|
ErrProtocolVersionMismatch
|
||
|
ErrNetworkIdMismatch
|
||
|
ErrGenesisBlockMismatch
|
||
|
ErrNoStatusMsg
|
||
|
ErrExtraStatusMsg
|
||
|
ErrSuspendedPeer
|
||
|
ErrUselessPeer
|
||
|
ErrRequestRejected
|
||
|
ErrUnexpectedResponse
|
||
|
ErrInvalidResponse
|
||
|
ErrTooManyTimeouts
|
||
|
ErrHandshakeMissingKey
|
||
|
)
|
||
|
|
||
|
func (e errCode) String() string {
|
||
|
return errorToString[int(e)]
|
||
|
}
|
||
|
|
||
|
// XXX change once legacy code is out
|
||
|
var errorToString = map[int]string{
|
||
|
ErrMsgTooLarge: "Message too long",
|
||
|
ErrDecode: "Invalid message",
|
||
|
ErrInvalidMsgCode: "Invalid message code",
|
||
|
ErrProtocolVersionMismatch: "Protocol version mismatch",
|
||
|
ErrNetworkIdMismatch: "NetworkId mismatch",
|
||
|
ErrGenesisBlockMismatch: "Genesis block mismatch",
|
||
|
ErrNoStatusMsg: "No status message",
|
||
|
ErrExtraStatusMsg: "Extra status message",
|
||
|
ErrSuspendedPeer: "Suspended peer",
|
||
|
ErrRequestRejected: "Request rejected",
|
||
|
ErrUnexpectedResponse: "Unexpected response",
|
||
|
ErrInvalidResponse: "Invalid response",
|
||
|
ErrTooManyTimeouts: "Too many request timeouts",
|
||
|
ErrHandshakeMissingKey: "Key missing from handshake message",
|
||
|
}
|
||
|
|
||
|
type chainManager interface {
|
||
|
GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash)
|
||
|
GetBlock(hash common.Hash) (block *types.Block)
|
||
|
Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash)
|
||
|
}
|
||
|
|
||
|
// announceData is the network packet for the block announcements.
|
||
|
type announceData 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
|
||
|
ReorgDepth uint64
|
||
|
Update keyValueList
|
||
|
|
||
|
haveHeaders uint64 // we have the headers of the remote peer's chain up to this number
|
||
|
headKnown bool
|
||
|
requested bool
|
||
|
next *announceData
|
||
|
}
|
||
|
|
||
|
type blockInfo 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
|
||
|
}
|
||
|
|
||
|
// getBlockHashesData is the network packet for the hash based hash retrieval.
|
||
|
type getBlockHashesData struct {
|
||
|
Hash common.Hash
|
||
|
Amount uint64
|
||
|
}
|
||
|
|
||
|
// getBlockHeadersData represents a block header query.
|
||
|
type getBlockHeadersData struct {
|
||
|
Origin hashOrNumber // Block from which to retrieve headers
|
||
|
Amount uint64 // Maximum number of headers to retrieve
|
||
|
Skip uint64 // Blocks to skip between consecutive headers
|
||
|
Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
|
||
|
}
|
||
|
|
||
|
// hashOrNumber is a combined field for specifying an origin block.
|
||
|
type hashOrNumber struct {
|
||
|
Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
|
||
|
Number uint64 // Block hash from which to retrieve headers (excludes Hash)
|
||
|
}
|
||
|
|
||
|
// EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the
|
||
|
// two contained union fields.
|
||
|
func (hn *hashOrNumber) EncodeRLP(w io.Writer) error {
|
||
|
if hn.Hash == (common.Hash{}) {
|
||
|
return rlp.Encode(w, hn.Number)
|
||
|
}
|
||
|
if hn.Number != 0 {
|
||
|
return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
|
||
|
}
|
||
|
return rlp.Encode(w, hn.Hash)
|
||
|
}
|
||
|
|
||
|
// DecodeRLP is a specialized decoder for hashOrNumber to decode the contents
|
||
|
// into either a block hash or a block number.
|
||
|
func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error {
|
||
|
_, size, _ := s.Kind()
|
||
|
origin, err := s.Raw()
|
||
|
if err == nil {
|
||
|
switch {
|
||
|
case size == 32:
|
||
|
err = rlp.DecodeBytes(origin, &hn.Hash)
|
||
|
case size <= 8:
|
||
|
err = rlp.DecodeBytes(origin, &hn.Number)
|
||
|
default:
|
||
|
err = fmt.Errorf("invalid input size %d for origin", size)
|
||
|
}
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// newBlockData is the network packet for the block propagation message.
|
||
|
type newBlockData struct {
|
||
|
Block *types.Block
|
||
|
TD *big.Int
|
||
|
}
|
||
|
|
||
|
// blockBodiesData is the network packet for block content distribution.
|
||
|
type blockBodiesData []*types.Body
|
||
|
|
||
|
// CodeData is the network response packet for a node data retrieval.
|
||
|
type CodeData []struct {
|
||
|
Value []byte
|
||
|
}
|
||
|
|
||
|
type proofsData [][]rlp.RawValue
|