Added better prediction of waku RLP key type and value
This commit is contained in:
parent
a50e35b72d
commit
900bad769a
|
@ -1,8 +1,11 @@
|
||||||
package waku
|
package waku
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -202,28 +205,36 @@ loop:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o statusOptions) decodeKey(s *rlp.Stream) (statusOptionKey, statusOptionKeyType, error) {
|
func (o statusOptions) decodeKey(s *rlp.Stream) (statusOptionKey, statusOptionKeyType, error) {
|
||||||
var key statusOptionKey
|
// Problem: A string will be encoded to bytes, and bytes can be decoded into a uint.
|
||||||
|
// This means that an encoded string that is attempted to be decoded into a uint will succeed and return a valid uint.
|
||||||
|
// This is bad because wildly inaccurate keys can be returned. See below examples:
|
||||||
|
// - string("0"); encodes to byte(48); decodes to uint(48).
|
||||||
|
// - string("111"); encodes to []byte(131, 49, 49, 49); decode to uint(3223857).
|
||||||
|
// This means an expected index of 0 will be returned as 48. An expected index of 111 will be returned as 3223857
|
||||||
|
|
||||||
// If statusOptionKey (uint) can be decoded return it
|
// Solution: We need to first test if the RLP stream can be decoded into a string.
|
||||||
// Ignore the first error and attempt string decoding
|
// If a stream can be decoded into a string, attempt to decode the string into a uint.
|
||||||
if err := s.Decode(&key); err == nil {
|
// If decoding the string into a uint is successful return the value.
|
||||||
return key, sOKTU, nil
|
// If decoding the string failed, attempt to decode as a uint. Return the result or error from this final step.
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt decoding into a string
|
// decode into bytes, detect if bytes can be parsed as a string and from a string to a uint
|
||||||
var sKey string
|
var bKey []byte
|
||||||
if err := s.Decode(&sKey); err != nil {
|
if err := s.Decode(&bKey); err != nil {
|
||||||
return key, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse string into uint
|
// Parse string into uint
|
||||||
uKey, err := strconv.ParseUint(sKey, 10, 64)
|
uKey, err := strconv.ParseUint(string(bKey), 10, 64)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return key, 0, err
|
return statusOptionKey(uKey), sOKTS, err
|
||||||
}
|
}
|
||||||
|
|
||||||
key = statusOptionKey(uKey)
|
// If statusOptionKey (uint) can be decoded return it
|
||||||
return key, sOKTS, nil
|
buf := bytes.NewBuffer(bKey)
|
||||||
|
uintKey, c := binary.ReadUvarint(buf)
|
||||||
|
spew.Dump(uintKey, c)
|
||||||
|
|
||||||
|
return statusOptionKey(uintKey), sOKTU, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setKeyType sets a statusOptions' keyType if it hasn't previously been set
|
// setKeyType sets a statusOptions' keyType if it hasn't previously been set
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package waku
|
package waku
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -36,18 +38,87 @@ func TestEncodeDecodeRLP(t *testing.T) {
|
||||||
require.EqualValues(t, opts, optsDecoded)
|
require.EqualValues(t, opts, optsDecoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackwardCompatibility(t *testing.T) {
|
// TODO remove once key type issue is resolved.
|
||||||
alist := []interface{}{
|
func TestKeyTypes(t *testing.T) {
|
||||||
[]interface{}{"0", math.Float64bits(2.05)},
|
uKeys := []uint{
|
||||||
|
0, 1, 2, 49, 50, 256, 257, 1000, 6000,
|
||||||
}
|
}
|
||||||
data, err := rlp.EncodeToBytes(alist)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var optsDecoded statusOptions
|
for i, uKey := range uKeys {
|
||||||
err = rlp.DecodeBytes(data, &optsDecoded)
|
fmt.Printf("test %d, for key '%d'", i+1, uKey)
|
||||||
require.NoError(t, err)
|
|
||||||
|
encodeable := []interface{}{
|
||||||
|
[]interface{}{uKey, true},
|
||||||
|
}
|
||||||
|
data, err := rlp.EncodeToBytes(encodeable)
|
||||||
|
spew.Dump(data, err)
|
||||||
|
|
||||||
|
var optsDecoded statusOptions
|
||||||
|
err = rlp.DecodeBytes(data, &optsDecoded)
|
||||||
|
spew.Dump(optsDecoded, err)
|
||||||
|
|
||||||
|
println("\n----------------\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBackwardCompatibility(t *testing.T) {
|
||||||
pow := math.Float64bits(2.05)
|
pow := math.Float64bits(2.05)
|
||||||
require.EqualValues(t, statusOptions{PoWRequirement: &pow}, optsDecoded)
|
lne := true
|
||||||
|
|
||||||
|
cs := []struct {
|
||||||
|
Input []interface{}
|
||||||
|
Expected statusOptions
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{"0", pow},
|
||||||
|
},
|
||||||
|
statusOptions{PoWRequirement: &pow, keyType: sOKTS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{"2", true},
|
||||||
|
},
|
||||||
|
statusOptions{LightNodeEnabled: &lne, keyType: sOKTS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{uint(2), true},
|
||||||
|
},
|
||||||
|
statusOptions{LightNodeEnabled: &lne, keyType: sOKTU},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{uint(0), pow},
|
||||||
|
},
|
||||||
|
statusOptions{PoWRequirement: &pow, keyType: sOKTU},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{"1000", true},
|
||||||
|
},
|
||||||
|
statusOptions{keyType: sOKTS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]interface{}{
|
||||||
|
[]interface{}{uint(1000), true},
|
||||||
|
},
|
||||||
|
statusOptions{keyType: sOKTU},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cs {
|
||||||
|
failMsg := fmt.Sprintf("test '%d'", i+1)
|
||||||
|
|
||||||
|
data, err := rlp.EncodeToBytes(c.Input)
|
||||||
|
require.NoError(t, err, failMsg)
|
||||||
|
|
||||||
|
var optsDecoded statusOptions
|
||||||
|
err = rlp.DecodeBytes(data, &optsDecoded)
|
||||||
|
require.NoError(t, err, failMsg)
|
||||||
|
|
||||||
|
require.EqualValues(t, c.Expected, optsDecoded, failMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForwardCompatibility(t *testing.T) {
|
func TestForwardCompatibility(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue