Refactor to waku handshake keyType identification
Presuming that all RLP keys will be of the same type. Still failing on forward and backward compatibility, so I will fidn a solution for this next
This commit is contained in:
parent
c16eba55f6
commit
042ae30f9f
|
@ -18,12 +18,6 @@ type statusOptionKey uint
|
||||||
// statusOptionKeyType is a type of a statusOptions key used for a particular instance of statusOptions struct.
|
// statusOptionKeyType is a type of a statusOptions key used for a particular instance of statusOptions struct.
|
||||||
type statusOptionKeyType uint
|
type statusOptionKeyType uint
|
||||||
|
|
||||||
type statusOptionKeyToType struct {
|
|
||||||
Idx int
|
|
||||||
Key statusOptionKey
|
|
||||||
Type statusOptionKeyType
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sOKTS statusOptionKeyType = iota + 1 // Status Option Key Type String
|
sOKTS statusOptionKeyType = iota + 1 // Status Option Key Type String
|
||||||
sOKTU // Status Option Key Type Uint
|
sOKTU // Status Option Key Type Uint
|
||||||
|
@ -35,11 +29,6 @@ var (
|
||||||
keyFieldIdx = make(map[statusOptionKey]int)
|
keyFieldIdx = make(map[statusOptionKey]int)
|
||||||
)
|
)
|
||||||
|
|
||||||
type keyTypeMapping struct {
|
|
||||||
idxFieldKey map[int]*statusOptionKeyToType
|
|
||||||
keyFieldIdx map[statusOptionKey]*statusOptionKeyToType
|
|
||||||
}
|
|
||||||
|
|
||||||
// statusOptions defines additional information shared between peers
|
// statusOptions defines additional information shared between peers
|
||||||
// during the handshake.
|
// during the handshake.
|
||||||
// There might be more options provided then fields in statusOptions
|
// There might be more options provided then fields in statusOptions
|
||||||
|
@ -53,7 +42,7 @@ type statusOptions struct {
|
||||||
ConfirmationsEnabled *bool `rlp:"key=3"`
|
ConfirmationsEnabled *bool `rlp:"key=3"`
|
||||||
RateLimits *RateLimits `rlp:"key=4"`
|
RateLimits *RateLimits `rlp:"key=4"`
|
||||||
TopicInterest []TopicType `rlp:"key=5"`
|
TopicInterest []TopicType `rlp:"key=5"`
|
||||||
keyTypeMapping keyTypeMapping
|
keyType statusOptionKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
// initFLPKeyFields initialises the values of `idxFieldKey` and `keyFieldIdx`
|
// initFLPKeyFields initialises the values of `idxFieldKey` and `keyFieldIdx`
|
||||||
|
@ -74,10 +63,14 @@ func initRLPKeyFields() error {
|
||||||
|
|
||||||
keys := strings.Split(rlpTag, "=")
|
keys := strings.Split(rlpTag, "=")
|
||||||
|
|
||||||
// parse keys[1] as an int
|
if len(keys) != 2 || keys[0] != "key" {
|
||||||
|
panic("invalid value of \"rlp\" tag, expected \"key=N\" where N is uint")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse keys[1] as an uint
|
||||||
key, err := strconv.ParseUint(keys[1], 10, 64)
|
key, err := strconv.ParseUint(keys[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("malformed rlp tag '%s', tag should be formatted 'rlp:\"key=0\"': %v", rlpTag, err)
|
return fmt.Errorf("malformed rlp tag '%s', expected \"key=N\" where N is uint: %v", rlpTag, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// typecast key to be of statusOptionKey type
|
// typecast key to be of statusOptionKey type
|
||||||
|
@ -151,25 +144,8 @@ func (o statusOptions) EncodeRLP(w io.Writer) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var val []interface{}
|
|
||||||
|
|
||||||
if o.keyTypeMapping.idxFieldKey == nil {
|
|
||||||
val = append(val, key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
k, ok := o.keyTypeMapping.idxFieldKey[i]
|
|
||||||
if !ok {
|
|
||||||
val = append(val, key, value)
|
|
||||||
} else {
|
|
||||||
ke, err := k.encode()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("key encoding fail: %v", err)
|
|
||||||
}
|
|
||||||
val = append(val, ke, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if value != nil {
|
if value != nil {
|
||||||
optionsList = append(optionsList, val)
|
optionsList = append(optionsList, []interface{}{o.encodeKey(key), value})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, optionsList)
|
return rlp.Encode(w, optionsList)
|
||||||
|
@ -194,30 +170,25 @@ loop:
|
||||||
return fmt.Errorf("expected an inner list: %v", err)
|
return fmt.Errorf("expected an inner list: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ktt := statusOptionKeyToType{}
|
key, keyType, err := o.decodeKey(s)
|
||||||
if err = ktt.decodeStream(s); err != nil {
|
o.setKeyType(keyType)
|
||||||
return fmt.Errorf("invalid key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip processing if a key does not exist.
|
// Skip processing if a key does not exist.
|
||||||
// It might happen when there is a new peer
|
// It might happen when there is a new peer
|
||||||
// which supports a new option with
|
// which supports a new option with
|
||||||
// a higher index.
|
// a higher index.
|
||||||
idx, ok := keyFieldIdx[ktt.Key]
|
idx, ok := keyFieldIdx[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Read the rest of the list items and dump them.
|
// Read the rest of the list items and dump them.
|
||||||
_, err := s.Raw()
|
_, err := s.Raw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read the value of key %d: %v", ktt.Key, err)
|
return fmt.Errorf("failed to read the value of key %d: %v", key, err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ktt.Idx = idx
|
|
||||||
o.addKeyToType(&ktt)
|
|
||||||
|
|
||||||
if err := s.Decode(v.Elem().Field(idx).Addr().Interface()); err != nil {
|
if err := s.Decode(v.Elem().Field(idx).Addr().Interface()); err != nil {
|
||||||
return fmt.Errorf("failed to decode an option %d: %v", ktt.Key, err)
|
return fmt.Errorf("failed to decode an option %d: %v", key, err)
|
||||||
}
|
}
|
||||||
if err := s.ListEnd(); err != nil {
|
if err := s.ListEnd(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -227,58 +198,46 @@ loop:
|
||||||
return s.ListEnd()
|
return s.ListEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *statusOptions) addKeyToType(ktt *statusOptionKeyToType) {
|
func (o statusOptions) decodeKey(s *rlp.Stream) (statusOptionKey, statusOptionKeyType, error) {
|
||||||
|
|
||||||
if o.keyTypeMapping.idxFieldKey == nil {
|
|
||||||
o.keyTypeMapping.idxFieldKey = make(map[int]*statusOptionKeyToType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.keyTypeMapping.keyFieldIdx == nil {
|
|
||||||
o.keyTypeMapping.keyFieldIdx = make(map[statusOptionKey]*statusOptionKeyToType)
|
|
||||||
}
|
|
||||||
|
|
||||||
o.keyTypeMapping.idxFieldKey[ktt.Idx] = ktt
|
|
||||||
o.keyTypeMapping.keyFieldIdx[ktt.Key] = ktt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *statusOptionKeyToType) decodeStream(s *rlp.Stream) error {
|
|
||||||
var key statusOptionKey
|
var key statusOptionKey
|
||||||
|
|
||||||
// If uint can be decoded return it
|
// If statusOptionKey (uint) can be decoded return it
|
||||||
|
// Ignore the first error and attempt string decoding
|
||||||
if err := s.Decode(&key); err == nil {
|
if err := s.Decode(&key); err == nil {
|
||||||
k.Key = key
|
return key, sOKTU, nil
|
||||||
k.Type = sOKTU
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt decoding into a string
|
// Attempt decoding into a string
|
||||||
var sKey string
|
var sKey string
|
||||||
if err := s.Decode(&sKey); err != nil {
|
if err := s.Decode(&sKey); err != nil {
|
||||||
return err
|
return key, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse string into uint
|
// Parse string into uint
|
||||||
uKey, err := strconv.ParseUint(sKey, 10, 64)
|
uKey, err := strconv.ParseUint(sKey, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return key, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
k.Key = statusOptionKey(uKey)
|
key = statusOptionKey(uKey)
|
||||||
k.Type = sOKTS
|
return key, sOKTS, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k statusOptionKeyToType) encode() (interface{}, error) {
|
// setKeyType sets a statusOptions' keyType if it hasn't previously been set
|
||||||
switch k.Type {
|
func (o *statusOptions) setKeyType(t statusOptionKeyType) {
|
||||||
case sOKTU:
|
if o.keyType == 0 {
|
||||||
return k.Key, nil
|
o.keyType = t
|
||||||
case sOKTS:
|
|
||||||
return fmt.Sprint(k.Key), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("failed to encode key '%d', unknown key type '%d'", k.Key, k.Type)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o statusOptions) encodeKey(key statusOptionKey) interface{} {
|
||||||
|
if o.keyType == sOKTS {
|
||||||
|
return fmt.Sprint(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
func (o statusOptions) Validate() error {
|
func (o statusOptions) Validate() error {
|
||||||
if len(o.TopicInterest) > 1000 {
|
if len(o.TopicInterest) > 1000 {
|
||||||
return errors.New("topic interest is limited by 1000 items")
|
return errors.New("topic interest is limited by 1000 items")
|
||||||
|
|
|
@ -25,6 +25,7 @@ func TestEncodeDecodeRLP(t *testing.T) {
|
||||||
TopicLimits: 1,
|
TopicLimits: 1,
|
||||||
},
|
},
|
||||||
TopicInterest: []TopicType{{0x01}, {0x02}, {0x03}, {0x04}},
|
TopicInterest: []TopicType{{0x01}, {0x02}, {0x03}, {0x04}},
|
||||||
|
keyType: sOKTU,
|
||||||
}
|
}
|
||||||
data, err := rlp.EncodeToBytes(opts)
|
data, err := rlp.EncodeToBytes(opts)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
Loading…
Reference in New Issue