Skip to content

Commit 3708a8f

Browse files
prestonvanloonrauljordan
authored andcommitted
Add tool and script for interop testing (prysmaticlabs#3417)
* add tool and script for interop testing * identity * lint * merge upstream, fix conflict, update script, add comment * add comma separated support for --peer= * remove NUM_VALIDATORS, comma fix * WIP docker image * use CI builder * pr feedback * whatever antoine says * ignore git in docker * jobs=auto * disable remote cache * try to cache the golang part * try to cache the golang part * nvm * From Antoine with love * fix
1 parent af07c13 commit 3708a8f

File tree

12 files changed

+261
-13
lines changed

12 files changed

+261
-13
lines changed

.dockerignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bazel-*
2+
.git

beacon-chain/node/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ go_library(
2626
"//shared/featureconfig:go_default_library",
2727
"//shared/params:go_default_library",
2828
"//shared/prometheus:go_default_library",
29+
"//shared/sliceutil:go_default_library",
2930
"//shared/tracing:go_default_library",
3031
"//shared/version:go_default_library",
3132
"@com_github_ethereum_go_ethereum//common:go_default_library",

beacon-chain/node/node.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/prysmaticlabs/prysm/shared/featureconfig"
3535
"github.com/prysmaticlabs/prysm/shared/params"
3636
"github.com/prysmaticlabs/prysm/shared/prometheus"
37+
"github.com/prysmaticlabs/prysm/shared/sliceutil"
3738
"github.com/prysmaticlabs/prysm/shared/tracing"
3839
"github.com/prysmaticlabs/prysm/shared/version"
3940
"github.com/sirupsen/logrus"
@@ -213,7 +214,7 @@ func (b *BeaconNode) registerP2P(ctx *cli.Context) error {
213214

214215
svc, err := p2p.NewService(&p2p.Config{
215216
NoDiscovery: ctx.GlobalBool(cmd.NoDiscovery.Name),
216-
StaticPeers: ctx.GlobalStringSlice(cmd.StaticPeers.Name),
217+
StaticPeers: sliceutil.SplitCommaSeparated(ctx.GlobalStringSlice(cmd.StaticPeers.Name)),
217218
BootstrapNodeAddr: bootnodeENR,
218219
RelayNodeAddr: ctx.GlobalString(cmd.RelayNode.Name),
219220
HostAddress: ctx.GlobalString(cmd.P2PHost.Name),

interop.Dockerfile

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM gcr.io/prysmaticlabs/build-agent AS builder
2+
3+
WORKDIR /workspace
4+
5+
COPY . /workspace/.
6+
7+
# Build binaries for minimal configuration.
8+
RUN bazel build --define ssz=minimal --jobs=auto --remote_cache= \
9+
//beacon-chain \
10+
//validator \
11+
//tools/interop/convert-keys
12+
13+
14+
FROM gcr.io/whiteblock/base:ubuntu1804
15+
16+
COPY --from=builder /workspace/bazel-bin/beacon-chain/linux_amd64_stripped/beacon-chain .
17+
COPY --from=builder /workspace/bazel-bin/validator/linux_amd64_pure_stripped/validator .
18+
COPY --from=builder /workspace/bazel-bin/tools/interop/convert-keys/linux_amd64_stripped/convert-keys .
19+
20+
RUN mkdir /launch
21+
22+
COPY scripts/interop_start.sh /launch/start.sh
23+
24+
ENTRYPOINT ["start.sh"]

scripts/interop_start.sh

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/bin/bash
2+
3+
"""
4+
2019/09/08 -- Interop start script.
5+
This script is intended for dockerfile deployment for interop testing.
6+
This script is fragile and subject to break as flags change.
7+
Use at your own risk!
8+
9+
10+
Use with interop.Dockerfile from the workspace root:
11+
12+
docker build -f interop.Dockerfile .
13+
"""
14+
15+
# Flags
16+
IDENTITY="" # P2P private key
17+
PEERS="" # Comma separated list of peers
18+
GEN_STATE="" # filepath to ssz encoded state.
19+
PORT="8000" # port to serve p2p traffic
20+
YAML_KEY_FILE="" # Path to yaml keyfile as defined here: https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start
21+
22+
# Constants
23+
BEACON_LOG_FILE="/tmp/beacon.log"
24+
VALIDATOR_LOG_FILE="/tmp/validator.log"
25+
26+
usage() {
27+
echo "--identity=<identity>"
28+
echo "--peer=<peer>"
29+
echo "--num-validators=<number>"
30+
echo "--gen-state=<file path>"
31+
port "--port=<port number>"
32+
}
33+
34+
while [ "$1" != "" ];
35+
do
36+
PARAM=`echo $1 | awk -F= '{print $1}'`
37+
VALUE=`echo $1 | sed 's/^[^=]*=//g'`
38+
39+
case $PARAM in
40+
--identity)
41+
IDENTITY=$VALUE
42+
;;
43+
--peers)
44+
PEERS+=",$VALUE"
45+
;;
46+
--validator-keys)
47+
YAML_KEY_FILE=$VALUE
48+
;;
49+
--gen-state)
50+
GEN_STATE=$VALUE
51+
;;
52+
--port)
53+
PORT=$VALUE
54+
;;
55+
--help)
56+
usage
57+
exit
58+
;;
59+
*)
60+
echo "ERROR: unknown parameter \"$PARAM\""
61+
usage
62+
exit 1
63+
;;
64+
esac
65+
shift
66+
done
67+
68+
69+
echo "Converting hex yaml keys to a format that Prysm understands"
70+
71+
# Expect YAML keys in hex encoded format. Convert this into the format the the validator already understands.
72+
./convert-keys $YAML_KEY_FILE /tmp/keys.json
73+
74+
echo "Starting beacon chain and logging to $BEACON_LOG_FILE"
75+
76+
BEACON_FLAGS="--bootstrap-node= \
77+
--deposit-contract=0xD775140349E6A5D12524C6ccc3d6A1d4519D4029 \
78+
--p2p-port=$PORT \
79+
--peer=$PEERS \
80+
--interop-genesis-state=$GEN_STATE \
81+
--p2p-priv-key=$IDENTITY \
82+
--log-file=$BEACON_LOG_FILE"
83+
84+
./beacon-chain $BEACON_FLAGS &
85+
86+
echo "Starting validator client and logging to $VALIDATOR_LOG_FILE"
87+
88+
VALIDATOR_FLAGS="--monitoring-port=9091 \
89+
--unencrypted-keys /tmp/keys.json \
90+
--log-file=$VALIDATOR_LOG_FILE
91+
92+
./validator- $VALIDATOR_FLAGS &
93+

shared/sliceutil/slice.go

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package sliceutil
22

3+
import (
4+
"strings"
5+
)
6+
37
// SubsetUint64 returns true if the first array is
48
// completely contained in the second array with time
59
// complexity of approximately o(n).
@@ -259,3 +263,12 @@ func IntersectionByteSlices(s ...[][]byte) [][]byte {
259263
}
260264
return inter
261265
}
266+
267+
// SplitCommaSeparated values from the list. Example: []string{"a,b", "c,d"} becomes []string{"a", "b", "c", "d"}.
268+
func SplitCommaSeparated(arr []string) []string {
269+
var result []string
270+
for _, val := range arr {
271+
result = append(result, strings.Split(val, ",")...)
272+
}
273+
return result
274+
}

shared/sliceutil/slice_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,29 @@ func TestIntersectionByteSlices(t *testing.T) {
352352
}
353353
}
354354
}
355+
356+
func TestSplitCommaSeparated(t *testing.T) {
357+
tests := []struct {
358+
input []string
359+
output []string
360+
}{
361+
{
362+
input: []string{"a,b", "c,d"},
363+
output: []string{"a", "b", "c", "d"},
364+
},
365+
{
366+
input: []string{"a", "b,c,d"},
367+
output: []string{"a", "b", "c", "d"},
368+
},
369+
{
370+
input: []string{"a", "b", "c"},
371+
output: []string{"a", "b", "c"},
372+
},
373+
}
374+
375+
for _, tt := range tests {
376+
if result := SplitCommaSeparated(tt.input); !reflect.DeepEqual(result, tt.output) {
377+
t.Errorf("SplitCommaSeparated(%v) = %v; wanted %v", tt.input, result, tt.output)
378+
}
379+
}
380+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["main.go"],
6+
importpath = "github.com/prysmaticlabs/prysm/tools/interop/convert-keys",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//tools/unencrypted-keys-gen:go_default_library",
10+
"@in_gopkg_yaml_v2//:go_default_library",
11+
],
12+
)
13+
14+
go_binary(
15+
name = "convert-keys",
16+
embed = [":go_default_library"],
17+
visibility = ["//visibility:public"],
18+
)

tools/interop/convert-keys/main.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Used for converting keys.yaml files from eth2.0-pm for interop testing.
2+
// See: https://github.com/ethereum/eth2.0-pm/tree/master/interop/mocked_start
3+
//
4+
// This code can be discarded after interop testing.
5+
package main
6+
7+
import (
8+
"encoding/hex"
9+
"fmt"
10+
"io/ioutil"
11+
"log"
12+
"os"
13+
14+
"gopkg.in/yaml.v2"
15+
keygen "github.com/prysmaticlabs/prysm/tools/unencrypted-keys-gen"
16+
)
17+
18+
// KeyPair with hex encoded data.
19+
type KeyPair struct {
20+
Priv string `yaml:"privkey"`
21+
Pub string `yaml:"pubkey"`
22+
}
23+
24+
// KeyPairs represent the data format in the upstream yaml.
25+
type KeyPairs []KeyPair
26+
27+
func main() {
28+
if len(os.Args) < 3 {
29+
fmt.Println("Usage: convert-keys path/to/keys.yaml path/to/output.json")
30+
return
31+
}
32+
inFile := os.Args[1]
33+
34+
in, err := ioutil.ReadFile(inFile)
35+
if err != nil {
36+
log.Fatalf("Failed to read file %s: %v", inFile, err)
37+
}
38+
data := make(KeyPairs, 0)
39+
if err := yaml.Unmarshal(in, &data); err != nil {
40+
log.Fatalf("Failed to unmarshal yaml: %v", err)
41+
}
42+
43+
out := &keygen.UnencryptedKeysContainer{}
44+
for _, key := range data {
45+
pk, err := hex.DecodeString(key.Priv[2:])
46+
if err != nil {
47+
log.Fatalf("Failed to decode hex string %s: %v", key.Priv, err)
48+
}
49+
50+
out.Keys = append(out.Keys, &keygen.UnencryptedKeys{
51+
ValidatorKey: pk,
52+
WithdrawalKey: pk,
53+
})
54+
}
55+
56+
outFile, err := os.Create(os.Args[2])
57+
if err != nil {
58+
log.Fatalf("Failed to create file at %s: %v", os.Args[2], err)
59+
}
60+
defer outFile.Close()
61+
if err := keygen.SaveUnencryptedKeysToFile(outFile, out); err != nil {
62+
log.Fatalf("Failed to save %v", err)
63+
}
64+
log.Printf("Wrote %s\n", os.Args[2])
65+
}

tools/unencrypted-keys-gen/BUILD.bazel

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ go_library(
44
name = "go_default_library",
55
srcs = ["main.go"],
66
importpath = "github.com/prysmaticlabs/prysm/tools/unencrypted-keys-gen",
7-
visibility = ["//visibility:private"],
7+
visibility = [
8+
"//tools/interop/convert-keys:__pkg__",
9+
],
810
deps = [
911
"//shared/bls:go_default_library",
1012
],

tools/unencrypted-keys-gen/main.go

+12-9
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ var (
1818
overwrite = flag.Bool("overwrite", false, "If the key file exists, it will be overwritten")
1919
)
2020

21-
type unencryptedKeysContainer struct {
22-
Keys []*unencryptedKeys `json:"keys"`
21+
// UnencryptedKeysContainer defines the structure of the unecrypted key JSON file.
22+
type UnencryptedKeysContainer struct {
23+
Keys []*UnencryptedKeys `json:"keys"`
2324
}
2425

25-
type unencryptedKeys struct {
26+
// UnencryptedKeys is the inner struct of the JSON file.
27+
type UnencryptedKeys struct {
2628
ValidatorKey []byte `json:"validator_key"`
2729
WithdrawalKey []byte `json:"withdrawal_key"`
2830
}
@@ -53,14 +55,14 @@ func main() {
5355
}()
5456

5557
ctnr := generateUnencryptedKeys(rand.Reader)
56-
if err := saveUnencryptedKeysToFile(file, ctnr); err != nil {
58+
if err := SaveUnencryptedKeysToFile(file, ctnr); err != nil {
5759
log.Fatal(err)
5860
}
5961
}
6062

61-
func generateUnencryptedKeys(r io.Reader) *unencryptedKeysContainer {
62-
ctnr := &unencryptedKeysContainer{
63-
Keys: make([]*unencryptedKeys, *numKeys),
63+
func generateUnencryptedKeys(r io.Reader) *UnencryptedKeysContainer {
64+
ctnr := &UnencryptedKeysContainer{
65+
Keys: make([]*UnencryptedKeys, *numKeys),
6466
}
6567
for i := 0; i < *numKeys; i++ {
6668
signingKey, err := bls.RandKey(r)
@@ -71,15 +73,16 @@ func generateUnencryptedKeys(r io.Reader) *unencryptedKeysContainer {
7173
if err != nil {
7274
log.Fatal(err)
7375
}
74-
ctnr.Keys[i] = &unencryptedKeys{
76+
ctnr.Keys[i] = &UnencryptedKeys{
7577
ValidatorKey: signingKey.Marshal(),
7678
WithdrawalKey: withdrawalKey.Marshal(),
7779
}
7880
}
7981
return ctnr
8082
}
8183

82-
func saveUnencryptedKeysToFile(w io.Writer, ctnr *unencryptedKeysContainer) error {
84+
// SaveUnencryptedKeysToFile JSON encodes the container and writes to the writer.
85+
func SaveUnencryptedKeysToFile(w io.Writer, ctnr *UnencryptedKeysContainer) error {
8386
enc, err := json.Marshal(ctnr)
8487
if err != nil {
8588
log.Fatal(err)

tools/unencrypted-keys-gen/main_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
func TestSavesUnencryptedKeys(t *testing.T) {
1212
ctnr := generateUnencryptedKeys(rand.Reader)
1313
buf := new(bytes.Buffer)
14-
if err := saveUnencryptedKeysToFile(buf, ctnr); err != nil {
14+
if err := SaveUnencryptedKeysToFile(buf, ctnr); err != nil {
1515
t.Fatal(err)
1616
}
1717
enc := buf.Bytes()
18-
dec := &unencryptedKeysContainer{}
18+
dec := &UnencryptedKeysContainer{}
1919
if err := json.Unmarshal(enc, dec); err != nil {
2020
t.Fatal(err)
2121
}

0 commit comments

Comments
 (0)