Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

swarm/network: Use different privatekey for bzz overlay in sim #1304

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
55bddb5
cmd/swarm, p2p, swarm: Enable ENR in binary/execadapter
nolash Mar 18, 2019
9bf14a5
cmd/p2p/swarm: Remove comments + config.Enode nomarshal
nolash Mar 18, 2019
d2dbcc9
p2p/simulations: Remove superfluous error check
nolash Mar 18, 2019
a279d2f
p2p/simulation: Move init enode comment
nolash Mar 20, 2019
6d7141a
swarm, p2p/simulations, cmd/swarm: Use nodekey in binary record sign
nolash Mar 21, 2019
eea82be
swarm/network, swarm/pss: Dervice bzzkey
nolash Mar 19, 2019
e297d3f
swarm/pss: Remove unused function
nolash Mar 19, 2019
6220dd5
swarm/network: Store swarm private key in simulation bucket
nolash Mar 19, 2019
c6b56e6
swarm/pss: Shorten TextProxNetwork shortrunning test timeout
nolash Mar 19, 2019
02d0602
swarm/pss: Increase prox test timeout
nolash Mar 19, 2019
0b7c515
swarm/pss: Increase timeout slightly on shortrunning proxtest
nolash Mar 19, 2019
09e2d59
swarm/network: Simplify bucket instantiation in servicectx func
nolash Mar 19, 2019
1819686
p2p/simulations: Tcpport -> udpport
nolash Mar 20, 2019
9a268da
swarm/network, swarm/pss: Simplify + correct lock in servicefunc sim
nolash Mar 20, 2019
5edbf3c
swarm/network: Cleanup after rebase on extract swarm enode new
nolash Mar 21, 2019
d8b4e7a
p2p/simulations, swarm/network: Make exec disc test pass
nolash Mar 21, 2019
2d5b3c3
swarm/network: Prune ye olde comment
nolash Mar 21, 2019
d2ad11c
swarm/pss: Correct revised bzzkey method call
nolash Mar 21, 2019
b254021
swarm/network: Clarify comment about privatekey generation data
nolash Mar 22, 2019
ac56987
swarm/pss: Fix syntax errors after rebase
nolash Mar 22, 2019
4d6fdb5
swarm/network: Rename misleadingly named method
nolash Mar 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions p2p/simulations/adapters/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,14 +411,13 @@ func startExecNodeStack() (*node.Node, error) {
if err := json.Unmarshal([]byte(confEnv), &conf); err != nil {
return nil, fmt.Errorf("error decoding %s: %v", envNodeConfig, err)
}
// TODO verify that ListenAddr will contain the correct tcp addr
// if we should start using exec adapters with other host than local

// create enode record
nodeTcpConn, err := net.ResolveTCPAddr("tcp", conf.Stack.P2P.ListenAddr)
if err != nil {
conf.Node.initDummyEnode()
} else {
conf.Node.initEnode(nodeTcpConn.IP, nodeTcpConn.Port, nodeTcpConn.Port)
if nodeTcpConn.IP == nil {
nodeTcpConn.IP = net.IPv4(127, 0, 0, 1)
}
conf.Node.initEnode(nodeTcpConn.IP, nodeTcpConn.Port, nodeTcpConn.Port)
conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey
conf.Stack.Logger = log.New("node.id", conf.Node.ID.String())

Expand Down
2 changes: 1 addition & 1 deletion p2p/simulations/adapters/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error {
n.Record.Set(&enrIp)
enrTcpPort := enr.TCP(tcpport)
n.Record.Set(&enrTcpPort)
enrUdpPort := enr.UDP(tcpport)
enrUdpPort := enr.UDP(udpport)
n.Record.Set(&enrUdpPort)

err := enode.SignV4(&n.Record, n.PrivateKey)
Expand Down
32 changes: 28 additions & 4 deletions swarm/network/simulation/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@
package simulation

import (
"bytes"
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"io/ioutil"
"math/rand"
"os"
"sync"
"time"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/swarm/network"
)

var (
BucketKeyBzzPrivateKey BucketKey = "bzzprivkey"
)

// NodeIDs returns NodeIDs for all nodes in the network.
func (s *Simulation) NodeIDs() (ids []enode.ID) {
nodes := s.Net.GetNodes()
Expand Down Expand Up @@ -104,20 +112,24 @@ func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) {
// for now we have no way of setting bootnodes or lightnodes in sims
// so we just let them be set to false
// they should perhaps be possible to override them with AddNodeOption
enodeParams := &network.EnodeParams{
PrivateKey: conf.PrivateKey,
}
record, err := network.NewEnodeRecord(enodeParams)
bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf)
if err != nil {
return enode.ID{}, err
}

enodeParams := &network.EnodeParams{
PrivateKey: bzzPrivateKey,
}
record, err := network.NewEnodeRecord(enodeParams)
conf.Record = *record

// Add the bzz address to the node config
node, err := s.Net.NewNodeWithConfig(conf)
if err != nil {
return id, err
}
s.buckets[node.ID()] = new(sync.Map)
frncmx marked this conversation as resolved.
Show resolved Hide resolved
s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey)

return node.ID(), s.Net.Start(node.ID())
}
Expand Down Expand Up @@ -315,3 +327,15 @@ func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) {
func init() {
rand.Seed(time.Now().UnixNano())
}

// derive a private key for swarm for the node key
// returns the private key used to generate the bzz key
func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) {
// pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data
privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you extract []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a} into a variable so that we don't have magic constants? What these hex number anyway? I don't know what they mean.

Copy link
Contributor Author

@nolash nolash Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hint: hex.

And I tend to think that a bit of cryptic easter egg fun in the code raises spirits. You don't agree, perhaps?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see these are hex numbers, but still magic constants. <- 🔥

So, I guess I disagree.
As I feel we already have enough cryptic code to understand. 😉
Let's make fun of solving the already existing puzzles first. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make fun of solving the already existing puzzles first.

That would be magic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun is ok bzz, but why are we doing this again? what was wrong with this?

bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf))
if err != nil {
return nil, err
}
return bzzPrivateKey, nil
}
9 changes: 6 additions & 3 deletions swarm/network/simulation/simulation.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,16 @@ func New(services map[string]ServiceFunc) (s *Simulation) {
name, serviceFunc := name, serviceFunc
s.serviceNames = append(s.serviceNames, name)
adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) {
b := new(sync.Map)
s.mu.Lock()
defer s.mu.Unlock()
b, ok := s.buckets[ctx.Config.ID]
nolash marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
b = new(sync.Map)
}
service, cleanup, err := serviceFunc(ctx, b)
if err != nil {
return nil, err
}
s.mu.Lock()
defer s.mu.Unlock()
if cleanup != nil {
s.cleanupFuncs = append(s.cleanupFuncs, cleanup)
}
Expand Down
1 change: 0 additions & 1 deletion swarm/network/simulations/discovery/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ func BenchmarkDiscovery_128_4(b *testing.B) { benchmarkDiscovery(b, 128, 4) }
func BenchmarkDiscovery_256_4(b *testing.B) { benchmarkDiscovery(b, 256, 4) }

func TestDiscoverySimulationExecAdapter(t *testing.T) {
t.Skip("This is left broken pending ENR preparations for swarm binary. Execadapter is not currently in use, so a short pause won't hurt")
testDiscoverySimulationExecAdapter(t, *nodeCount, *initCount)
}

Expand Down
81 changes: 57 additions & 24 deletions swarm/pss/prox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pss

import (
"context"
"crypto/ecdsa"
"encoding/binary"
"errors"
"fmt"
Expand Down Expand Up @@ -88,7 +89,7 @@ func (d *testData) setDone() {
d.handlerDone = true
}

func getCmdParams(t *testing.T) (int, int) {
func getCmdParams(t *testing.T) (int, int, time.Duration) {
frncmx marked this conversation as resolved.
Show resolved Hide resolved
args := strings.Split(t.Name(), "/")
msgCount, err := strconv.ParseInt(args[2], 10, 16)
if err != nil {
Expand All @@ -98,7 +99,12 @@ func getCmdParams(t *testing.T) (int, int) {
if err != nil {
t.Fatal(err)
}
return int(msgCount), int(nodeCount)
timeoutStr := fmt.Sprintf("%ss", args[3])
frncmx marked this conversation as resolved.
Show resolved Hide resolved
frncmx marked this conversation as resolved.
Show resolved Hide resolved
timeoutDur, err := time.ParseDuration(timeoutStr)
if err != nil {
t.Fatal(err)
}
return int(msgCount), int(nodeCount), timeoutDur
}

func newTestData() *testData {
Expand All @@ -117,11 +123,27 @@ func newTestData() *testData {
}
}

func (d *testData) init(msgCount int) {
func (d *testData) getKademlia(nodeId *enode.ID) (*network.Kademlia, error) {
kadif, ok := d.sim.NodeItem(*nodeId, simulation.BucketKeyKademlia)
if !ok {
return nil, fmt.Errorf("no kademlia entry for %v", nodeId)
}
kad, ok := kadif.(*network.Kademlia)
if !ok {
return nil, fmt.Errorf("invalid kademlia entry for %v", nodeId)
}
return kad, nil
}

func (d *testData) init(msgCount int) error {
log.Debug("TestProxNetwork start")

for _, nodeId := range d.sim.NodeIDs() {
d.nodeAddrs[nodeId] = nodeIDToAddr(nodeId)
kad, err := d.getKademlia(&nodeId)
if err != nil {
return err
}
d.nodeAddrs[nodeId] = kad.BaseAddr()
}

for i := 0; i < int(msgCount); i++ {
Expand Down Expand Up @@ -169,6 +191,7 @@ func (d *testData) init(msgCount int) {
log.Debug("nn for msg", "targets", len(d.recipients[i]), "msgidx", i, "msg", common.Bytes2Hex(msgAddr[:8]), "sender", d.senders[i], "senderpo", smallestPo)
}
log.Debug("msgs to receive", "count", d.requiredMessages)
return nil
}

// Here we test specific functionality of the pss, setting the prox property of
Expand All @@ -190,37 +213,40 @@ func (d *testData) init(msgCount int) {
// nodes Y and Z will be considered required recipients of the msg,
// whereas nodes X, Y and Z will be allowed recipients.
func TestProxNetwork(t *testing.T) {
t.Run("16/16", testProxNetwork)
t.Run("16/16/15", testProxNetwork)
}

// params in run name: nodes/msgs
func TestProxNetworkLong(t *testing.T) {
if !*longrunning {
t.Skip("run with --longrunning flag to run extensive network tests")
}
t.Run("8/100", testProxNetwork)
t.Run("16/100", testProxNetwork)
t.Run("32/100", testProxNetwork)
t.Run("64/100", testProxNetwork)
t.Run("128/100", testProxNetwork)
t.Run("8/100/30", testProxNetwork)
frncmx marked this conversation as resolved.
Show resolved Hide resolved
t.Run("16/100/30", testProxNetwork)
t.Run("32/100/60", testProxNetwork)
t.Run("64/100/60", testProxNetwork)
t.Run("128/100/120", testProxNetwork)
}

func testProxNetwork(t *testing.T) {
tstdata := newTestData()
msgCount, nodeCount := getCmdParams(t)
msgCount, nodeCount, timeout := getCmdParams(t)
handlerContextFuncs := make(map[Topic]handlerContextFunc)
handlerContextFuncs[topic] = nodeMsgHandler
services := newProxServices(tstdata, true, handlerContextFuncs, tstdata.kademlias)
tstdata.sim = simulation.New(services)
defer tstdata.sim.Close()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
filename := fmt.Sprintf("testdata/snapshot_%d.json", nodeCount)
err := tstdata.sim.UploadSnapshot(ctx, filename)
if err != nil {
t.Fatal(err)
}
tstdata.init(msgCount) // initialize the test data
err = tstdata.init(msgCount) // initialize the test data
if err != nil {
t.Fatal(err)
}
wrapper := func(c context.Context, _ *simulation.Simulation) error {
return testRoutine(tstdata, c)
}
Expand All @@ -230,7 +256,7 @@ func testProxNetwork(t *testing.T) {
// however, it might just mean that not all possible messages are received
// now we must check if all required messages are received
cnt := tstdata.getMsgCount()
log.Debug("TestProxNetwork finnished", "rcv", cnt)
log.Debug("TestProxNetwork finished", "rcv", cnt)
if cnt < tstdata.requiredMessages {
t.Fatal(result.Error)
}
Expand Down Expand Up @@ -354,7 +380,7 @@ func nodeMsgHandler(tstdata *testData, config *adapters.NodeConfig) *handler {
// replaces pss_test.go when those tests are rewritten to the new swarm/network/simulation package
func newProxServices(tstdata *testData, allowRaw bool, handlerContextFuncs map[Topic]handlerContextFunc, kademlias map[enode.ID]*network.Kademlia) map[string]simulation.ServiceFunc {
stateStore := state.NewInmemoryStore()
kademlia := func(id enode.ID) *network.Kademlia {
kademlia := func(id enode.ID, bzzkey []byte) *network.Kademlia {
if k, ok := kademlias[id]; ok {
return k
}
Expand All @@ -364,25 +390,32 @@ func newProxServices(tstdata *testData, allowRaw bool, handlerContextFuncs map[T
params.MaxRetries = 1000
params.RetryExponent = 2
params.RetryInterval = 1000000
kademlias[id] = network.NewKademlia(id[:], params)
kademlias[id] = network.NewKademlia(bzzkey, params)
return kademlias[id]
}
return map[string]simulation.ServiceFunc{
"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
var err error
var bzzPrivateKey *ecdsa.PrivateKey
// normally translation of enode id to swarm address is concealed by the network package
// however, we need to keep track of it in the test driver as well.
// if the translation in the network package changes, that can cause these tests to unpredictably fail
// therefore we keep a local copy of the translation here
addr := network.NewAddr(ctx.Config.Node())
addr.OAddr = nodeIDToAddr(ctx.Config.Node().ID())
bzzPrivateKey, err = simulation.BzzPrivateKeyFromConfig(ctx.Config)
if err != nil {
return nil, nil, err
}
addr.OAddr = network.PrivateKeyToBzzKey(bzzPrivateKey)
b.Store(simulation.BucketKeyBzzPrivateKey, bzzPrivateKey)
hp := network.NewHiveParams()
hp.Discovery = false
config := &network.BzzConfig{
OverlayAddr: addr.Over(),
UnderlayAddr: addr.Under(),
HiveParams: hp,
}
return network.NewBzz(config, kademlia(ctx.Config.ID), stateStore, nil, nil), nil, nil
return network.NewBzz(config, kademlia(ctx.Config.ID, addr.OAddr), stateStore, nil, nil), nil, nil
},
"pss": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
// execadapter does not exec init()
Expand All @@ -395,7 +428,12 @@ func newProxServices(tstdata *testData, allowRaw bool, handlerContextFuncs map[T
privkey, err := w.GetPrivateKey(keys)
pssp := NewPssParams().WithPrivateKey(privkey)
pssp.AllowRaw = allowRaw
pskad := kademlia(ctx.Config.ID)
bzzPrivateKey, err := simulation.BzzPrivateKeyFromConfig(ctx.Config)
if err != nil {
return nil, nil, err
}
bzzKey := network.PrivateKeyToBzzKey(bzzPrivateKey)
pskad := kademlia(ctx.Config.ID, bzzKey)
ps, err := NewPss(pskad, pssp)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -433,8 +471,3 @@ func newProxServices(tstdata *testData, allowRaw bool, handlerContextFuncs map[T
},
}
}

// makes sure we create the addresses the same way in driver and service setup
func nodeIDToAddr(id enode.ID) []byte {
return id.Bytes()
}