Implemented RLP key field initialisation

This replaces the statically declared values, which previously replaced function varialbes see https://github.com/status-im/status-go/pull/1931#discussion_r406123786
This commit is contained in:
Samuel Hawksby-Robinson 2020-04-09 16:26:02 +01:00 committed by Andrea Maria Piana
parent 91e1bdc8ce
commit c16eba55f6
3 changed files with 72 additions and 61 deletions

View File

@ -7,6 +7,7 @@ import (
"math" "math"
"reflect" "reflect"
"strconv" "strconv"
"strings"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -30,22 +31,8 @@ const (
var ( var (
defaultMinPoW = math.Float64bits(0.001) defaultMinPoW = math.Float64bits(0.001)
idxFieldKey = map[int]statusOptionKey{ idxFieldKey = make(map[int]statusOptionKey)
0: 0, keyFieldIdx = make(map[statusOptionKey]int)
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
}
keyFieldIdx = map[statusOptionKey]int{
0: 0,
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
}
) )
type keyTypeMapping struct { type keyTypeMapping struct {
@ -69,6 +56,38 @@ type statusOptions struct {
keyTypeMapping keyTypeMapping keyTypeMapping keyTypeMapping
} }
// initFLPKeyFields initialises the values of `idxFieldKey` and `keyFieldIdx`
func initRLPKeyFields() error {
o := statusOptions{}
v := reflect.ValueOf(o)
for i := 0; i < v.NumField(); i++ {
// skip unexported fields
if !v.Field(i).CanInterface() {
continue
}
rlpTag := v.Type().Field(i).Tag.Get("rlp")
// skip fields without rlp field tag
if rlpTag == "" {
continue
}
keys := strings.Split(rlpTag, "=")
// parse keys[1] as an int
key, err := strconv.ParseUint(keys[1], 10, 64)
if err != nil {
return fmt.Errorf("malformed rlp tag '%s', tag should be formatted 'rlp:\"key=0\"': %v", rlpTag, err)
}
// typecast key to be of statusOptionKey type
keyFieldIdx[statusOptionKey(key)] = i
idxFieldKey[i] = statusOptionKey(key)
}
return nil
}
// WithDefaults adds the default values for a given peer. // WithDefaults adds the default values for a given peer.
// This are not the host default values, but the default values that ought to // This are not the host default values, but the default values that ought to
// be used when receiving from an update from a peer. // be used when receiving from an update from a peer.

View File

@ -2,9 +2,6 @@ package waku
import ( import (
"math" "math"
"reflect"
"strconv"
"strings"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -67,60 +64,47 @@ func TestForwardCompatibility(t *testing.T) {
require.EqualValues(t, statusOptions{PoWRequirement: &pow}, optsDecoded) require.EqualValues(t, statusOptions{PoWRequirement: &pow}, optsDecoded)
} }
func TestStatusOptionKeys(t *testing.T) { func TestInitRLPKeyFields(t *testing.T) {
o := statusOptions{} ifk := map[int]statusOptionKey{
0: 0,
kfi := make(map[statusOptionKey]int) 1: 1,
ifk := make(map[int]statusOptionKey) 2: 2,
3: 3,
v := reflect.ValueOf(o) 4: 4,
5: 5,
for i := 0; i < v.NumField(); i++ {
// skip unexported fields
if !v.Field(i).CanInterface() {
continue
} }
rlpTag := v.Type().Field(i).Tag.Get("rlp") kfi := map[statusOptionKey]int{
// skip fields without rlp field tag 0: 0,
if rlpTag == "" { 1: 1,
continue 2: 2,
3: 3,
4: 4,
5: 5,
} }
keys := strings.Split(rlpTag, "=") // Test that the kfi length matches the inited global keyFieldIdx length
require.Equal(t, 2, len(keys)) require.Equal(t, len(kfi), len(keyFieldIdx))
// parse keys[1] as an int // Test that each index of the kfi values matches the inited global keyFieldIdx of the same index
key, err := strconv.ParseUint(keys[1], 10, 64)
require.NoError(t, err)
// typecast key to be of statusOptionKey type
kfi[statusOptionKey(key)] = i
ifk[i] = statusOptionKey(key)
}
// Test that the statusOptions' derived kfi length matches the global keyFieldIdx length
require.Equal(t, len(keyFieldIdx), len(kfi))
// Test that each index of the statusOptions' derived kfi values matches the global keyFieldIdx of the same index
for k, v := range kfi { for k, v := range kfi {
require.Exactly(t, keyFieldIdx[k], v) require.Exactly(t, v, keyFieldIdx[k])
} }
// Test that each index of the global keyFieldIdx values matches statusOptions' derived kfi values of the same index // Test that each index of the inited global keyFieldIdx values matches kfi values of the same index
for k, v := range keyFieldIdx { for k, v := range keyFieldIdx {
require.Exactly(t, kfi[k], v) require.Exactly(t, v, kfi[k])
} }
// Test that the statusOptions' derived ifk length matches the global idxFieldKey length // Test that the ifk length matches the inited global idxFieldKey length
require.Equal(t, len(idxFieldKey), len(ifk)) require.Equal(t, len(ifk), len(idxFieldKey))
// Test that each index of the statusOptions' derived ifk values matches the global idxFieldKey of the same index // Test that each index of the ifk values matches the inited global idxFieldKey of the same index
for k, v := range ifk { for k, v := range ifk {
require.Exactly(t, idxFieldKey[k], v) require.Exactly(t, v, idxFieldKey[k])
} }
// Test that each index of the global idxFieldKey values matches statusOptions' derived ifk values of the same index // Test that each index of the inited global idxFieldKey values matches ifk values of the same index
for k, v := range idxFieldKey { for k, v := range idxFieldKey {
require.Exactly(t, ifk[k], v) require.Exactly(t, v, ifk[k])
} }
} }

View File

@ -108,6 +108,14 @@ type Waku struct {
logger *zap.Logger logger *zap.Logger
} }
// init initialises the waku package
func init() {
err := initRLPKeyFields()
if err != nil {
panic(err)
}
}
// New creates a Waku client ready to communicate through the Ethereum P2P network. // New creates a Waku client ready to communicate through the Ethereum P2P network.
func New(cfg *Config, logger *zap.Logger) *Waku { func New(cfg *Config, logger *zap.Logger) *Waku {
if cfg == nil { if cfg == nil {