les: UDP pre-negotiation of available server capacity (#22183)
This PR implements the first one of the "lespay" UDP queries which is already useful in itself: the capacity query. The server pool is making use of this query by doing a cheap UDP query to determine whether it is worth starting the more expensive TCP connection process.
This commit is contained in:
180
les/vflux/requests.go
Normal file
180
les/vflux/requests.go
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2020 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 vflux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
var ErrNoReply = errors.New("no reply for given request")
|
||||
|
||||
const (
|
||||
MaxRequestLength = 16 // max number of individual requests in a batch
|
||||
CapacityQueryName = "cq"
|
||||
CapacityQueryMaxLen = 16
|
||||
)
|
||||
|
||||
type (
|
||||
// Request describes a single vflux request inside a batch. Service and request
|
||||
// type are identified by strings, parameters are RLP encoded.
|
||||
Request struct {
|
||||
Service, Name string
|
||||
Params []byte
|
||||
}
|
||||
// Requests are a batch of vflux requests
|
||||
Requests []Request
|
||||
|
||||
// Replies are the replies to a batch of requests
|
||||
Replies [][]byte
|
||||
|
||||
// CapacityQueryReq is the encoding format of the capacity query
|
||||
CapacityQueryReq struct {
|
||||
Bias uint64 // seconds
|
||||
AddTokens []IntOrInf
|
||||
}
|
||||
// CapacityQueryReq is the encoding format of the response to the capacity query
|
||||
CapacityQueryReply []uint64
|
||||
)
|
||||
|
||||
// Add encodes and adds a new request to the batch
|
||||
func (r *Requests) Add(service, name string, val interface{}) (int, error) {
|
||||
enc, err := rlp.EncodeToBytes(val)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
*r = append(*r, Request{
|
||||
Service: service,
|
||||
Name: name,
|
||||
Params: enc,
|
||||
})
|
||||
return len(*r) - 1, nil
|
||||
}
|
||||
|
||||
// Get decodes the reply to the i-th request in the batch
|
||||
func (r Replies) Get(i int, val interface{}) error {
|
||||
if i < 0 || i >= len(r) {
|
||||
return ErrNoReply
|
||||
}
|
||||
return rlp.DecodeBytes(r[i], val)
|
||||
}
|
||||
|
||||
const (
|
||||
IntNonNegative = iota
|
||||
IntNegative
|
||||
IntPlusInf
|
||||
IntMinusInf
|
||||
)
|
||||
|
||||
// IntOrInf is the encoding format for arbitrary length signed integers that can also
|
||||
// hold the values of +Inf or -Inf
|
||||
type IntOrInf struct {
|
||||
Type uint8
|
||||
Value big.Int
|
||||
}
|
||||
|
||||
// BigInt returns the value as a big.Int or panics if the value is infinity
|
||||
func (i *IntOrInf) BigInt() *big.Int {
|
||||
switch i.Type {
|
||||
case IntNonNegative:
|
||||
return new(big.Int).Set(&i.Value)
|
||||
case IntNegative:
|
||||
return new(big.Int).Neg(&i.Value)
|
||||
case IntPlusInf:
|
||||
panic(nil) // caller should check Inf() before trying to convert to big.Int
|
||||
case IntMinusInf:
|
||||
panic(nil)
|
||||
}
|
||||
return &big.Int{} // invalid type decodes to 0 value
|
||||
}
|
||||
|
||||
// Inf returns 1 if the value is +Inf, -1 if it is -Inf, 0 otherwise
|
||||
func (i *IntOrInf) Inf() int {
|
||||
switch i.Type {
|
||||
case IntPlusInf:
|
||||
return 1
|
||||
case IntMinusInf:
|
||||
return -1
|
||||
}
|
||||
return 0 // invalid type decodes to 0 value
|
||||
}
|
||||
|
||||
// Int64 limits the value between MinInt64 and MaxInt64 (even if it is +-Inf) and returns an int64 type
|
||||
func (i *IntOrInf) Int64() int64 {
|
||||
switch i.Type {
|
||||
case IntNonNegative:
|
||||
if i.Value.IsInt64() {
|
||||
return i.Value.Int64()
|
||||
} else {
|
||||
return math.MaxInt64
|
||||
}
|
||||
case IntNegative:
|
||||
if i.Value.IsInt64() {
|
||||
return -i.Value.Int64()
|
||||
} else {
|
||||
return math.MinInt64
|
||||
}
|
||||
case IntPlusInf:
|
||||
return math.MaxInt64
|
||||
case IntMinusInf:
|
||||
return math.MinInt64
|
||||
}
|
||||
return 0 // invalid type decodes to 0 value
|
||||
}
|
||||
|
||||
// SetBigInt sets the value to the given big.Int
|
||||
func (i *IntOrInf) SetBigInt(v *big.Int) {
|
||||
if v.Sign() >= 0 {
|
||||
i.Type = IntNonNegative
|
||||
i.Value.Set(v)
|
||||
} else {
|
||||
i.Type = IntNegative
|
||||
i.Value.Neg(v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetInt64 sets the value to the given int64. Note that MaxInt64 translates to +Inf
|
||||
// while MinInt64 translates to -Inf.
|
||||
func (i *IntOrInf) SetInt64(v int64) {
|
||||
if v >= 0 {
|
||||
if v == math.MaxInt64 {
|
||||
i.Type = IntPlusInf
|
||||
} else {
|
||||
i.Type = IntNonNegative
|
||||
i.Value.SetInt64(v)
|
||||
}
|
||||
} else {
|
||||
if v == math.MinInt64 {
|
||||
i.Type = IntMinusInf
|
||||
} else {
|
||||
i.Type = IntNegative
|
||||
i.Value.SetInt64(-v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetInf sets the value to +Inf or -Inf
|
||||
func (i *IntOrInf) SetInf(sign int) {
|
||||
if sign == 1 {
|
||||
i.Type = IntPlusInf
|
||||
} else {
|
||||
i.Type = IntMinusInf
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user