mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Remove Accounts-V1 (#7532)
* remove accounts-v1 * get all tests to not panic * all client tests passing * fix node test * eliminate old flags * tidy up
This commit is contained in:
28
deps.bzl
28
deps.bzl
@@ -332,8 +332,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_coreos_go_systemd",
|
||||
importpath = "github.com/coreos/go-systemd",
|
||||
sum = "h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=",
|
||||
version = "v0.0.0-20181012123002-c6f51f82210d",
|
||||
sum = "h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=",
|
||||
version = "v0.0.0-20191104093116-d3cd4ed1dbcf",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_cpuguy83_go_md2man",
|
||||
@@ -590,8 +590,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_go_sql_driver_mysql",
|
||||
importpath = "github.com/go-sql-driver/mysql",
|
||||
sum = "h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=",
|
||||
version = "v1.5.0",
|
||||
sum = "h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=",
|
||||
version = "v1.4.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_golang_protobuf",
|
||||
@@ -784,8 +784,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_jmespath_go_jmespath",
|
||||
importpath = "github.com/jmespath/go-jmespath",
|
||||
sum = "h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=",
|
||||
version = "v0.3.0",
|
||||
sum = "h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=",
|
||||
version = "v0.0.0-20180206201540-c2b33e8439af",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_jrick_logrotate",
|
||||
@@ -868,8 +868,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_kr_pty",
|
||||
importpath = "github.com/kr/pty",
|
||||
sum = "h1:/Um6a/ZmD5tF7peoOJ5oN5KMQ0DrGVQSXLNwyckutPk=",
|
||||
version = "v1.1.3",
|
||||
sum = "h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=",
|
||||
version = "v1.1.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_kr_text",
|
||||
@@ -980,8 +980,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_mailru_easyjson",
|
||||
importpath = "github.com/mailru/easyjson",
|
||||
sum = "h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=",
|
||||
version = "v0.0.0-20190312143242-1de009706dbe",
|
||||
sum = "h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=",
|
||||
version = "v0.0.0-20180823135443-60711f1a8329",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_marten_seemann_qpack",
|
||||
@@ -1916,8 +1916,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_aws_aws_sdk_go",
|
||||
importpath = "github.com/aws/aws-sdk-go",
|
||||
sum = "h1:JiYid0lBDcM12HNOND5EcaBd1namBuB5BJ4Iex0DFMw=",
|
||||
version = "v1.33.15",
|
||||
sum = "h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk=",
|
||||
version = "v1.25.48",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_beorn7_perks",
|
||||
@@ -1976,8 +1976,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_golang_lint",
|
||||
importpath = "github.com/golang/lint",
|
||||
sum = "h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=",
|
||||
version = "v0.0.0-20180702182130-06c8688daad7",
|
||||
sum = "h1:ior8LN6127GsA53E9mD9nH/oP/LVbJplmLH5V8o+/Uk=",
|
||||
version = "v0.0.0-20170918230701-e5d664eb928e",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_golang_snappy",
|
||||
|
||||
6
go.mod
6
go.mod
@@ -6,7 +6,6 @@ require (
|
||||
contrib.go.opencensus.io/exporter/jaeger v0.2.0
|
||||
github.com/allegro/bigcache v1.2.1 // indirect
|
||||
github.com/aristanetworks/goarista v0.0.0-20200521140103-6c3304613b30
|
||||
github.com/aws/aws-sdk-go v1.33.15 // indirect
|
||||
github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d
|
||||
github.com/bazelbuild/rules_go v0.23.2
|
||||
github.com/cespare/cp v1.1.1 // indirect
|
||||
@@ -99,14 +98,9 @@ require (
|
||||
github.com/supranational/blst v0.1.2-alpha.1.0.20200917144033-cd0847a7580b
|
||||
github.com/tyler-smith/go-bip39 v1.0.2
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/wealdtech/eth2-signer-api v1.3.0
|
||||
github.com/wealdtech/go-bytesutil v1.1.1
|
||||
github.com/wealdtech/go-eth2-util v1.5.0
|
||||
github.com/wealdtech/go-eth2-wallet v1.12.0
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0
|
||||
github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2
|
||||
go.etcd.io/bbolt v1.3.4
|
||||
|
||||
38
go.sum
38
go.sum
@@ -73,10 +73,6 @@ github.com/aristanetworks/goarista v0.0.0-20200521140103-6c3304613b30/go.mod h1:
|
||||
github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.33.5 h1:p2fr1ryvNTU6avUWLI+/H7FGv0TBIjzVM5WDgXBBv4U=
|
||||
github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.33.15 h1:JiYid0lBDcM12HNOND5EcaBd1namBuB5BJ4Iex0DFMw=
|
||||
github.com/aws/aws-sdk-go v1.33.15/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d h1:lXjj6ngxx9PVxg6TtlMCbkPATwLFf5dcl9z5Jr3WqGg=
|
||||
github.com/bazelbuild/buildtools v0.0.0-20200528175155-f4e8394f069d/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU=
|
||||
github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM=
|
||||
@@ -246,7 +242,6 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
|
||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
|
||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -284,7 +279,6 @@ github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
@@ -448,8 +442,6 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d h1:k+SfYbN66Ev/GDVq39wYOXVW5RNd5kzzairbCe9dK5Q=
|
||||
github.com/joonix/log v0.0.0-20200409080653-9c1d2ceb5f1d/go.mod h1:fS54ONkjDV71zS9CDx3V9K21gJg7byKSvI4ajuWFNJw=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
@@ -947,8 +939,6 @@ github.com/schollz/progressbar/v3 v3.3.4/go.mod h1:Rp5lZwpgtYmlvmGo1FyDwXMqagyRB
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w=
|
||||
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y=
|
||||
github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I=
|
||||
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
@@ -1020,38 +1010,14 @@ github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/wealdtech/eth2-signer-api v1.3.0 h1:Fs0GfrdhboBKW7zaMvIvUHJaOB1ibpAmRG3lkB53in4=
|
||||
github.com/wealdtech/eth2-signer-api v1.3.0/go.mod h1:H8OpAoTBl6CaBvZEnhxWDjjWXNc3kwVFKWMAZd6sHlk=
|
||||
github.com/wealdtech/go-bytesutil v1.0.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
|
||||
github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc=
|
||||
github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
|
||||
github.com/wealdtech/go-ecodec v1.1.0 h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5Kr8o=
|
||||
github.com/wealdtech/go-ecodec v1.1.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.5.0 h1:L8sl3yoICAbn3134CBLNUt0o5h2voe0Es2KD5O9r8YQ=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.5.0/go.mod h1:321w9X26lAnNa/lQJi2A6Lap5IsNORoLwFPoJ1i8QvY=
|
||||
github.com/wealdtech/go-eth2-util v1.5.0 h1:b3fgyvoq/WocW9LkWT7zcO5VCKzKLCc97rPrk/B9oIc=
|
||||
github.com/wealdtech/go-eth2-util v1.5.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk=
|
||||
github.com/wealdtech/go-eth2-wallet v1.12.0 h1:nrwI3jPhehUhJGlBtNv/UmIo/57llvuVZZavLnfdQHI=
|
||||
github.com/wealdtech/go-eth2-wallet v1.12.0/go.mod h1:ouV+YSMbzk2dyecmofm8jhaMKdSigdIPMSnSqmWEfW8=
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0 h1:OZjjuxcIYo+EhAfph7lYP1z+VeNs9ruOI32kqtYe1Jg=
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0/go.mod h1:8r06Vpg/315/7Hl9CXq0ShQP8/cgUrBGzKKo6ywA4yQ=
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0 h1:CWb82xeNaZQt1Z829RyDALUy7UZbc6VOfTS+82jRdEQ=
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0/go.mod h1:JelKMM10UzDJNXdIcojMj6SCIsHC8NYn4c1S2FFk7OQ=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0 h1:UORXUYRoUYgYF96Y+QiBq33OKQVtn/nEjnSoQbe1UOA=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0/go.mod h1:Kc/8WcqMTczfH2xy5mDfCRd0NI/ca/j2jXmqJ7gz8yk=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0 h1:L1aPK9nc+8Ctcw+8I05vM6408weFc4a5RtLQDUeS0eE=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0/go.mod h1:e2q2uuEdq5+B3GE7jk+Mi9oz9V5nPPKXcXRg1XYavsU=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 h1:l9YV6OBqcxp5fjscK63lzuCUIye8ANACjJdpm5ULGS8=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1/go.mod h1:Zxhj/4i8nRpk4LTTqFKbfI2KyvO3uqLMerNXqKZKDK0=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 h1:+q7p58NvOEfEDw8NgEoNaSG/s1eFHpyg91NEobA6RF0=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI5bWuvjhanEyrD4MqTj8hIvt2Y=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0 h1:41H6hnVsI/csBx20UHpI2pY922N7Vhcro35DFS+slj0=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0/go.mod h1:XtXHbl4OV/XenQsvGmXbh+bVXaGS788oa30DB7kDInA=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0 h1:vBrH5icPPSeb14cdShA7/P2PBZOgZscJ2IhBlTIaFrA=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA=
|
||||
github.com/wealdtech/go-indexer v1.0.0 h1:/S4rfWQbSOnnYmwnvuTVatDibZ8o1s9bmTCHO16XINg=
|
||||
github.com/wealdtech/go-indexer v1.0.0/go.mod h1:u1cjsbsOXsm5jzJDyLmZY7GsrdX8KYXKBXkZcAmk3Zg=
|
||||
github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3 h1:shC1HB1UogxN5Ech3Yqaaxj1X/P656PPCB4RbojIJqc=
|
||||
github.com/wercker/journalhook v0.0.0-20180428041537-5d0a5ae867b3/go.mod h1:XCsSkdKK4gwBMNrOCZWww0pX6AOt+2gYc5Z6jBRrNVg=
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
|
||||
@@ -1117,14 +1083,12 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@@ -1375,7 +1339,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
@@ -1383,7 +1346,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
|
||||
@@ -53,7 +53,6 @@ type Flags struct {
|
||||
DisableUpdateHeadPerAttestation bool // DisableUpdateHeadPerAttestation will disabling update head on per attestation basis.
|
||||
EnableNoise bool // EnableNoise enables the beacon node to use NOISE instead of SECIO when performing a handshake with another peer.
|
||||
WaitForSynced bool // WaitForSynced uses WaitForSynced in validator startup to ensure it can communicate with the beacon node as soon as possible.
|
||||
EnableAccountsV2 bool // EnableAccountsV2 for Prysm validator clients.
|
||||
InitSyncVerbose bool // InitSyncVerbose logs every processed block during initial syncing.
|
||||
EnableFinalizedDepositsCache bool // EnableFinalizedDepositsCache enables utilization of cached finalized deposits.
|
||||
EnableEth1DataMajorityVote bool // EnableEth1DataMajorityVote uses the Voting With The Majority algorithm to vote for eth1data.
|
||||
@@ -259,16 +258,6 @@ func ConfigureValidator(ctx *cli.Context) {
|
||||
} else {
|
||||
log.Warn("Validator slashing protection not enabled!")
|
||||
}
|
||||
cfg.EnableAccountsV2 = true
|
||||
if ctx.Bool(disableAccountsV2.Name) {
|
||||
log.Warn("Disabling v2 of Prysm validator accounts")
|
||||
log.Error(
|
||||
"Accounts v1 will be fully deprecated in Prysm within the next 2 releases! If you are still " +
|
||||
"using this functionality, please begin to upgrade by creating a v2 wallet. More information can be " +
|
||||
"found in our docs portal https://docs.prylabs.network/docs/wallet/introduction/",
|
||||
)
|
||||
cfg.EnableAccountsV2 = false
|
||||
}
|
||||
if ctx.Bool(enableExternalSlasherProtectionFlag.Name) {
|
||||
log.Warn("Enabled validator attestation and block slashing protection using an external slasher.")
|
||||
cfg.SlasherProtection = true
|
||||
|
||||
@@ -20,19 +20,14 @@ go_library(
|
||||
"//shared/journald:go_default_library",
|
||||
"//shared/logutil:go_default_library",
|
||||
"//shared/maxprocs:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"//validator/accounts/v1:go_default_library",
|
||||
"//validator/accounts/v2:go_default_library",
|
||||
"//validator/client:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"//validator/node:go_default_library",
|
||||
"@com_github_joonix_log//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -63,7 +58,6 @@ go_image(
|
||||
"//shared/logutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"//validator/accounts/v1:go_default_library",
|
||||
"//validator/accounts/v2:go_default_library",
|
||||
"//validator/client:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"account.go",
|
||||
"status.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/validator/accounts/v1",
|
||||
visibility = [
|
||||
"//validator:__pkg__",
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//contracts/deposit-contract:go_default_library",
|
||||
"//shared/cmd:go_default_library",
|
||||
"//shared/depositutil:go_default_library",
|
||||
"//shared/fileutil:go_default_library",
|
||||
"//shared/keystore:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//validator/db/kv:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"account_test.go",
|
||||
"status_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//proto/slashing:go_default_library",
|
||||
"//shared/keystore:go_default_library",
|
||||
"//shared/mock:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"//validator/db/kv:go_default_library",
|
||||
"//validator/db/testing:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,354 +0,0 @@
|
||||
// Package accounts defines tools to manage an encrypted validator keystore.
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
contract "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
|
||||
"github.com/prysmaticlabs/prysm/shared/cmd"
|
||||
"github.com/prysmaticlabs/prysm/shared/depositutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/fileutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/keystore"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "accounts")
|
||||
|
||||
var errFailedToCloseDb = errors.New("failed to close the database")
|
||||
var errFailedToCloseManyDb = errors.New("failed to close one or more databases")
|
||||
|
||||
// DecryptKeysFromKeystore extracts a set of validator private keys from
|
||||
// an encrypted keystore directory and a password string.
|
||||
func DecryptKeysFromKeystore(directory, filePrefix, password string) (map[string]*keystore.Key, error) {
|
||||
ks := keystore.New(directory)
|
||||
validatorKeys, err := ks.GetKeys(directory, filePrefix, password, true)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get private key")
|
||||
}
|
||||
return validatorKeys, nil
|
||||
}
|
||||
|
||||
// VerifyAccountNotExists checks if a validator has not yet created an account
|
||||
// and keystore in the provided directory string.
|
||||
func VerifyAccountNotExists(directory, password string) error {
|
||||
if directory == "" || password == "" {
|
||||
return errors.New("expected a path to the validator keystore and password to be provided, received nil")
|
||||
}
|
||||
shardWithdrawalKeyFile := params.BeaconConfig().WithdrawalPrivkeyFileName
|
||||
validatorKeyFile := params.BeaconConfig().ValidatorPrivkeyFileName
|
||||
// First, if the keystore already exists, throws an error as there can only be
|
||||
// one keystore per validator client.
|
||||
ks := keystore.New(directory)
|
||||
if _, err := ks.GetKeys(directory, shardWithdrawalKeyFile, password, false); err == nil {
|
||||
return fmt.Errorf("keystore at path already exists: %s", shardWithdrawalKeyFile)
|
||||
}
|
||||
if _, err := ks.GetKeys(directory, validatorKeyFile, password, false); err == nil {
|
||||
return fmt.Errorf("keystore at path already exists: %s", validatorKeyFile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewValidatorAccount sets up a validator client's secrets and generates the necessary deposit data
|
||||
// parameters needed to deposit into the deposit contract on the ETH1.0 chain. Specifically, this
|
||||
// generates a BLS private and public key, and then logs the serialized deposit input hex string
|
||||
// to be used in an ETH1.0 transaction by the validator.
|
||||
func NewValidatorAccount(directory, password string) error {
|
||||
if password == "" {
|
||||
return errors.New("empty passphrase is not allowed")
|
||||
}
|
||||
log.Info(`Thanks, we are generating your keystore now, this could take a while...`)
|
||||
shardWithdrawalKeyFile := directory + params.BeaconConfig().WithdrawalPrivkeyFileName
|
||||
validatorKeyFile := directory + params.BeaconConfig().ValidatorPrivkeyFileName
|
||||
ks := keystore.New(directory)
|
||||
// If the keystore does not exists at the path, we create a new one for the validator.
|
||||
shardWithdrawalKey, err := keystore.NewKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shardWithdrawalKeyFile = shardWithdrawalKeyFile + hex.EncodeToString(shardWithdrawalKey.PublicKey.Marshal())[:12]
|
||||
if err := ks.StoreKey(shardWithdrawalKeyFile, shardWithdrawalKey, password); err != nil {
|
||||
return errors.Wrap(err, "unable to store key")
|
||||
}
|
||||
log.WithField(
|
||||
"path",
|
||||
shardWithdrawalKeyFile,
|
||||
).Info("Keystore generated for shard withdrawals at path")
|
||||
validatorKey, err := keystore.NewKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
validatorKeyFile = validatorKeyFile + hex.EncodeToString(validatorKey.PublicKey.Marshal())[:12]
|
||||
if err := ks.StoreKey(validatorKeyFile, validatorKey, password); err != nil {
|
||||
return errors.Wrap(err, "unable to store key")
|
||||
}
|
||||
log.WithField(
|
||||
"path",
|
||||
validatorKeyFile,
|
||||
).Info("Keystore generated for validator signatures at path")
|
||||
|
||||
log.Info(`Generating deposit data now, please wait...`)
|
||||
data, depositRoot, err := depositutil.DepositInput(
|
||||
validatorKey.SecretKey,
|
||||
shardWithdrawalKey.SecretKey,
|
||||
params.BeaconConfig().MaxEffectiveBalance,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to generate deposit data")
|
||||
}
|
||||
testAcc, err := contract.Setup()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create simulated backend")
|
||||
}
|
||||
testAcc.TxOpts.GasLimit = 1000000
|
||||
|
||||
tx, err := testAcc.Contract.Deposit(testAcc.TxOpts, data.PublicKey, data.WithdrawalCredentials, data.Signature, depositRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create deposit transaction")
|
||||
}
|
||||
log.Info(`Account creation complete! Copy and paste the raw deposit data shown below when issuing a transaction into the ETH1.0 deposit contract to activate your validator client`)
|
||||
fmt.Printf(`
|
||||
========================Deposit Data=======================
|
||||
|
||||
%#x
|
||||
|
||||
===================================================================
|
||||
`, tx.Data())
|
||||
fmt.Println("***Enter the above deposit data into step 3 on https://prylabs.net/participate***")
|
||||
publicKey := validatorKey.PublicKey.Marshal()
|
||||
log.Infof("Public key: %#x", publicKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exists checks if a validator account at a given keystore path exists.
|
||||
// assertNonEmpty is a boolean used to determine whether to check that
|
||||
// the provided directory exists.
|
||||
func Exists(keystorePath string, assertNonEmpty bool) (bool, error) {
|
||||
/* #nosec */
|
||||
f, err := os.Open(keystorePath)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if assertNonEmpty {
|
||||
_, err = f.Readdirnames(1) // Or f.Readdir(1)
|
||||
if errors.Is(err, io.EOF) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
||||
|
||||
// CreateValidatorAccount creates a validator account from the given cli context.
|
||||
func CreateValidatorAccount(path, passphrase string) (string, string, error) {
|
||||
// Forces user to create directory if using non-default path.
|
||||
if path != DefaultValidatorDir() {
|
||||
exists, err := Exists(path, false /* assertNonEmpty */)
|
||||
if err != nil {
|
||||
return path, passphrase, err
|
||||
}
|
||||
if !exists {
|
||||
return path, passphrase, fmt.Errorf("path %q does not exist", path)
|
||||
}
|
||||
}
|
||||
if err := NewValidatorAccount(path, passphrase); err != nil {
|
||||
return "", "", errors.Wrapf(err, "could not initialize validator account")
|
||||
}
|
||||
return path, passphrase, nil
|
||||
}
|
||||
|
||||
// PrintPublicAndPrivateKeys uses the passed in path and prints out the public and private keys in that directory.
|
||||
func PrintPublicAndPrivateKeys(path, passphrase string) error {
|
||||
keystores, err := DecryptKeysFromKeystore(path, params.BeaconConfig().ValidatorPrivkeyFileName, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to decrypt keystore keys at path %s", path)
|
||||
}
|
||||
for _, v := range keystores {
|
||||
fmt.Printf("Public key: %#x private key: %#x\n", v.PublicKey.Marshal(), v.SecretKey.Marshal())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultValidatorDir returns OS-specific default keystore directory.
|
||||
func DefaultValidatorDir() string {
|
||||
// Try to place the data folder in the user's home dir
|
||||
home := fileutil.HomeDir()
|
||||
if home != "" {
|
||||
if runtime.GOOS == "darwin" {
|
||||
return filepath.Join(home, "Library", "Eth2Validators")
|
||||
} else if runtime.GOOS == "windows" {
|
||||
return filepath.Join(home, "AppData", "Roaming", "Eth2Validators")
|
||||
} else {
|
||||
return filepath.Join(home, ".eth2validators")
|
||||
}
|
||||
}
|
||||
// As we cannot guess a stable location, return empty and handle later
|
||||
return ""
|
||||
}
|
||||
|
||||
// HandleEmptyKeystoreFlags checks what the set flags are and allows the user to manually enter them if they're empty.
|
||||
func HandleEmptyKeystoreFlags(cliCtx *cli.Context, confirmPassword bool) (string, string, error) {
|
||||
path := cliCtx.String(flags.KeystorePathFlag.Name)
|
||||
passphrase := cliCtx.String(flags.PasswordFlag.Name)
|
||||
|
||||
if path == "" {
|
||||
path = DefaultValidatorDir()
|
||||
log.Infof("Please specify the keystore path for your private keys (default: %q):", path)
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return path, passphrase, errors.Wrap(err, "could not read input path")
|
||||
}
|
||||
if text = strings.ReplaceAll(text, "\n", ""); text != "" {
|
||||
path = text
|
||||
}
|
||||
if text = strings.ReplaceAll(text, "\r", ""); text != "" {
|
||||
path = text
|
||||
}
|
||||
}
|
||||
|
||||
if passphrase == "" {
|
||||
log.Info("Please enter the password for your private keys")
|
||||
enteredPassphrase, err := cmd.EnterPassword(confirmPassword, cmd.StdInPasswordReader{})
|
||||
if err != nil {
|
||||
return path, enteredPassphrase, errors.Wrap(err, "could not read entered passphrase")
|
||||
}
|
||||
passphrase = enteredPassphrase
|
||||
}
|
||||
|
||||
return path, passphrase, nil
|
||||
}
|
||||
|
||||
// Merge merges data from validator databases in sourceDirectories into a new store, which is created in targetDirectory.
|
||||
func Merge(ctx context.Context, sourceDirectories []string, targetDirectory string) (err error) {
|
||||
var sourceStores []*kv.Store
|
||||
defer func() {
|
||||
failedToClose := false
|
||||
for _, store := range sourceStores {
|
||||
if deferErr := store.Close(); deferErr != nil {
|
||||
failedToClose = true
|
||||
}
|
||||
}
|
||||
if failedToClose {
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, errFailedToCloseManyDb.Error())
|
||||
} else {
|
||||
err = errFailedToCloseManyDb
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for _, dir := range sourceDirectories {
|
||||
store, err := kv.GetKVStore(dir)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to prepare the database in %s for merging", dir)
|
||||
}
|
||||
if store == nil {
|
||||
continue
|
||||
}
|
||||
sourceStores = append(sourceStores, store)
|
||||
}
|
||||
|
||||
if len(sourceStores) == 0 {
|
||||
return errors.New("no validator databases found in source directories")
|
||||
}
|
||||
|
||||
return kv.Merge(ctx, sourceStores, targetDirectory)
|
||||
}
|
||||
|
||||
// Split splits data from one validator database in sourceDirectory into several validator databases.
|
||||
// Each validator database is created in its own subdirectory inside targetDirectory.
|
||||
func Split(ctx context.Context, sourceDirectory, targetDirectory string) (err error) {
|
||||
var sourceStore *kv.Store
|
||||
sourceStore, err = kv.GetKVStore(sourceDirectory)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to prepare the source database for splitting")
|
||||
}
|
||||
if sourceStore == nil {
|
||||
return errors.New("no database found in source directory")
|
||||
}
|
||||
defer func() {
|
||||
if sourceStore != nil {
|
||||
if deferErr := sourceStore.Close(); deferErr != nil {
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, errFailedToCloseDb.Error())
|
||||
} else {
|
||||
err = errors.Wrap(deferErr, errFailedToCloseDb.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return kv.Split(ctx, sourceStore, targetDirectory)
|
||||
}
|
||||
|
||||
// ChangePassword changes the password for all keys located in a keystore.
|
||||
// Password is changed only for keys that can be decrypted using the old password.
|
||||
func ChangePassword(keystorePath, oldPassword, newPassword string) error {
|
||||
err := changePasswordForKeyType(
|
||||
keystorePath,
|
||||
params.BeaconConfig().ValidatorPrivkeyFileName,
|
||||
oldPassword,
|
||||
newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return changePasswordForKeyType(
|
||||
keystorePath,
|
||||
params.BeaconConfig().WithdrawalPrivkeyFileName,
|
||||
oldPassword,
|
||||
newPassword)
|
||||
}
|
||||
|
||||
func changePasswordForKeyType(keystorePath, filePrefix, oldPassword, newPassword string) error {
|
||||
keys, err := DecryptKeysFromKeystore(keystorePath, filePrefix, oldPassword)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to decrypt keys")
|
||||
}
|
||||
|
||||
keyStore := keystore.New(keystorePath)
|
||||
for _, key := range keys {
|
||||
keyFileName := keystorePath + filePrefix + hex.EncodeToString(key.PublicKey.Marshal())[:12]
|
||||
if err := keyStore.StoreKey(keyFileName, key, newPassword); err != nil {
|
||||
return errors.Wrapf(err, "failed to encrypt key %s with the new password", keyFileName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractPublicKeysFromKeyStore extracts only the public keys from the decrypted keys from the keystore.
|
||||
func ExtractPublicKeysFromKeyStore(keystorePath, passphrase string) ([][]byte, error) {
|
||||
decryptedKeys, err := DecryptKeysFromKeystore(keystorePath, params.BeaconConfig().ValidatorPrivkeyFileName, passphrase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not decrypt keys from keystore in path %s", keystorePath)
|
||||
}
|
||||
|
||||
i := 0
|
||||
pubkeys := make([][]byte, len(decryptedKeys))
|
||||
for _, key := range decryptedKeys {
|
||||
pubkeys[i] = key.PublicKey.Marshal()
|
||||
i++
|
||||
}
|
||||
|
||||
return pubkeys, nil
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
slashpb "github.com/prysmaticlabs/prysm/proto/slashing"
|
||||
"github.com/prysmaticlabs/prysm/shared/keystore"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
dbTest "github.com/prysmaticlabs/prysm/validator/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type sourceStoresHistory struct {
|
||||
ProposalEpoch uint64
|
||||
FirstStorePubKeyProposals bitfield.Bitlist
|
||||
SecondStorePubKeyProposals bitfield.Bitlist
|
||||
FirstStorePubKeyAttestations map[uint64]uint64
|
||||
SecondStorePubKeyAttestations map[uint64]uint64
|
||||
}
|
||||
|
||||
func TestNewValidatorAccount_AccountExists(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(directory))
|
||||
}()
|
||||
validatorKey, err := keystore.NewKey()
|
||||
require.NoError(t, err, "Cannot create new key")
|
||||
ks := keystore.New(directory)
|
||||
err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, "")
|
||||
require.NoError(t, err, "Unable to store key")
|
||||
require.NoError(t, NewValidatorAccount(directory, "passsword123"), "Should support multiple keys")
|
||||
files, err := ioutil.ReadDir(directory)
|
||||
assert.NoError(t, err)
|
||||
if len(files) != 3 {
|
||||
t.Errorf("multiple validators were not created only %v files in directory", len(files))
|
||||
for _, f := range files {
|
||||
t.Errorf("%v\n", f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewValidatorAccount_CreateValidatorAccount(t *testing.T) {
|
||||
t.Run("custom non-existent path", func(t *testing.T) {
|
||||
_, _, err := CreateValidatorAccount("foobar", "foobar")
|
||||
wantErrString := fmt.Sprintf("path %q does not exist", "foobar")
|
||||
assert.ErrorContains(t, wantErrString, err)
|
||||
})
|
||||
|
||||
t.Run("empty existing dir", func(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(directory), "Could not remove directory")
|
||||
}()
|
||||
|
||||
// Make sure that empty existing directory doesn't trigger any errors.
|
||||
require.NoError(t, os.Mkdir(directory, 0777))
|
||||
_, _, err := CreateValidatorAccount(directory, "foobar")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("empty string as password", func(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(directory), "Could not remove directory")
|
||||
}()
|
||||
require.NoError(t, os.Mkdir(directory, 0777))
|
||||
_, _, err := CreateValidatorAccount(directory, "")
|
||||
wantErrString := "empty passphrase is not allowed"
|
||||
assert.ErrorContains(t, wantErrString, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleEmptyFlags_FlagsSet(t *testing.T) {
|
||||
passedPath := "~/path/given"
|
||||
passedPassword := "password"
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.KeystorePathFlag.Name, passedPath, "set keystore path")
|
||||
set.String(flags.PasswordFlag.Name, passedPassword, "set keystore password")
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
path, passphrase, err := HandleEmptyKeystoreFlags(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, passedPath, path, "Expected set path to be unchanged")
|
||||
assert.Equal(t, passedPassword, passphrase, "Expected set password to be unchanged")
|
||||
}
|
||||
|
||||
func TestChangePassword_KeyEncryptedWithNewPassword(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(directory), "Could not remove directory")
|
||||
}()
|
||||
|
||||
oldPassword := "old"
|
||||
newPassword := "new"
|
||||
|
||||
validatorKey, err := keystore.NewKey()
|
||||
require.NoError(t, err, "Cannot create new key")
|
||||
ks := keystore.New(directory)
|
||||
err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, oldPassword)
|
||||
require.NoError(t, err, "Unable to store key")
|
||||
|
||||
require.NoError(t, ChangePassword(directory, oldPassword, newPassword))
|
||||
|
||||
keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())]
|
||||
assert.Equal(t, true, ok, "Key not encrypted using the new password")
|
||||
}
|
||||
|
||||
func TestChangePassword_KeyNotMatchingOldPasswordNotEncryptedWithNewPassword(t *testing.T) {
|
||||
directory := testutil.TempDir() + "/testkeystore"
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(directory), "Could not remove directory")
|
||||
}()
|
||||
|
||||
oldPassword := "old"
|
||||
newPassword := "new"
|
||||
|
||||
validatorKey, err := keystore.NewKey()
|
||||
require.NoError(t, err, "Cannot create new key")
|
||||
ks := keystore.New(directory)
|
||||
err = ks.StoreKey(directory+params.BeaconConfig().ValidatorPrivkeyFileName, validatorKey, "notmatching")
|
||||
require.NoError(t, err, "Unable to store key")
|
||||
|
||||
require.NoError(t, ChangePassword(directory, oldPassword, newPassword))
|
||||
|
||||
keys, err := DecryptKeysFromKeystore(directory, params.BeaconConfig().ValidatorPrivkeyFileName, newPassword)
|
||||
require.NoError(t, err)
|
||||
_, ok := keys[hex.EncodeToString(validatorKey.PublicKey.Marshal())]
|
||||
assert.Equal(t, false, ok, "Key incorrectly encrypted using the new password")
|
||||
}
|
||||
|
||||
func TestMerge_SucceedsWhenNoDatabaseExistsInSomeSourceDirectory(t *testing.T) {
|
||||
firstStorePubKey := [48]byte{1}
|
||||
firstStore := dbTest.SetupDB(t, [][48]byte{firstStorePubKey})
|
||||
secondStorePubKey := [48]byte{2}
|
||||
secondStore := dbTest.SetupDB(t, [][48]byte{secondStorePubKey})
|
||||
history, err := prepareSourcesForMerging(firstStorePubKey, firstStore.(*kv.Store), secondStorePubKey, secondStore.(*kv.Store))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, firstStore.Close(), "Closing source store failed")
|
||||
require.NoError(t, secondStore.Close(), "Closing source store failed")
|
||||
|
||||
sourceDirectoryWithoutStore := testutil.TempDir() + "/nodb"
|
||||
require.NoError(t, os.MkdirAll(sourceDirectoryWithoutStore, 0700), "Could not create directory")
|
||||
targetDirectory := testutil.TempDir() + "/target"
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, os.RemoveAll(targetDirectory), "Could not remove target directory")
|
||||
})
|
||||
|
||||
err = Merge(
|
||||
context.Background(),
|
||||
[]string{firstStore.DatabasePath(), secondStore.DatabasePath(), sourceDirectoryWithoutStore}, targetDirectory)
|
||||
require.NoError(t, err, "Merging failed")
|
||||
mergedStore, err := kv.GetKVStore(targetDirectory)
|
||||
require.NoError(t, err, "Retrieving the merged store failed")
|
||||
|
||||
assertMergedStore(t, mergedStore, firstStorePubKey, secondStorePubKey, history)
|
||||
}
|
||||
|
||||
func TestMerge_FailsWhenNoDatabaseExistsInAllSourceDirectories(t *testing.T) {
|
||||
sourceDirectory1 := testutil.TempDir() + "/source1"
|
||||
sourceDirectory2 := testutil.TempDir() + "/source2"
|
||||
targetDirectory := testutil.TempDir() + "/target"
|
||||
require.NoError(t, os.MkdirAll(sourceDirectory1, 0700), "Could not create directory")
|
||||
require.NoError(t, os.MkdirAll(sourceDirectory2, 0700), "Could not create directory")
|
||||
require.NoError(t, os.MkdirAll(targetDirectory, 0700), "Could not create directory")
|
||||
t.Cleanup(func() {
|
||||
for _, dir := range []string{sourceDirectory1, sourceDirectory2, targetDirectory} {
|
||||
assert.NoError(t, os.RemoveAll(dir), "Could not remove directory")
|
||||
}
|
||||
})
|
||||
|
||||
err := Merge(context.Background(), []string{sourceDirectory1, sourceDirectory2}, targetDirectory)
|
||||
expected := "no validator databases found in source directories"
|
||||
assert.ErrorContains(t, expected, err)
|
||||
}
|
||||
|
||||
func TestSplit(t *testing.T) {
|
||||
pubKeys := [][48]byte{{1}, {2}}
|
||||
sourceStore := dbTest.SetupDB(t, pubKeys)
|
||||
|
||||
proposalEpoch := uint64(0)
|
||||
proposalHistory1 := bitfield.Bitlist{0x01, 0x00, 0x00, 0x00, 0x01}
|
||||
err := sourceStore.SaveProposalHistoryForEpoch(context.Background(), pubKeys[0][:], proposalEpoch, proposalHistory1)
|
||||
require.NoError(t, err, "Saving proposal history failed")
|
||||
proposalHistory2 := bitfield.Bitlist{0x02, 0x00, 0x00, 0x00, 0x01}
|
||||
err = sourceStore.SaveProposalHistoryForEpoch(context.Background(), pubKeys[1][:], proposalEpoch, proposalHistory2)
|
||||
require.NoError(t, err, "Saving proposal history failed")
|
||||
|
||||
attestationHistoryMap1 := make(map[uint64]uint64)
|
||||
attestationHistoryMap1[0] = 0
|
||||
pubKeyAttestationHistory1 := &slashpb.AttestationHistory{
|
||||
TargetToSource: attestationHistoryMap1,
|
||||
LatestEpochWritten: 0,
|
||||
}
|
||||
attestationHistoryMap2 := make(map[uint64]uint64)
|
||||
attestationHistoryMap2[0] = 1
|
||||
pubKeyAttestationHistory2 := &slashpb.AttestationHistory{
|
||||
TargetToSource: attestationHistoryMap2,
|
||||
LatestEpochWritten: 0,
|
||||
}
|
||||
dbAttestationHistory := make(map[[48]byte]*slashpb.AttestationHistory)
|
||||
dbAttestationHistory[pubKeys[0]] = pubKeyAttestationHistory1
|
||||
dbAttestationHistory[pubKeys[1]] = pubKeyAttestationHistory2
|
||||
err = sourceStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory)
|
||||
require.NoError(t, err, "Saving attestation history failed %v")
|
||||
|
||||
require.NoError(t, sourceStore.Close(), "Closing source store failed")
|
||||
|
||||
targetDirectory := testutil.TempDir() + "/target"
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, os.RemoveAll(targetDirectory), "Could not remove target directory")
|
||||
})
|
||||
|
||||
require.NoError(t, Split(context.Background(), sourceStore.DatabasePath(), targetDirectory), "Splitting failed")
|
||||
}
|
||||
|
||||
func prepareSourcesForMerging(firstStorePubKey [48]byte, firstStore *kv.Store, secondStorePubKey [48]byte, secondStore *kv.Store) (*sourceStoresHistory, error) {
|
||||
proposalEpoch := uint64(0)
|
||||
proposalHistory1 := bitfield.Bitlist{0x01, 0x00, 0x00, 0x00, 0x01}
|
||||
if err := firstStore.SaveProposalHistoryForEpoch(context.Background(), firstStorePubKey[:], proposalEpoch, proposalHistory1); err != nil {
|
||||
return nil, errors.Wrapf(err, "Saving proposal history failed")
|
||||
}
|
||||
proposalHistory2 := bitfield.Bitlist{0x02, 0x00, 0x00, 0x00, 0x01}
|
||||
if err := secondStore.SaveProposalHistoryForEpoch(context.Background(), secondStorePubKey[:], proposalEpoch, proposalHistory2); err != nil {
|
||||
return nil, errors.Wrapf(err, "Saving proposal history failed")
|
||||
}
|
||||
|
||||
attestationHistoryMap1 := make(map[uint64]uint64)
|
||||
attestationHistoryMap1[0] = 0
|
||||
pubKeyAttestationHistory1 := &slashpb.AttestationHistory{
|
||||
TargetToSource: attestationHistoryMap1,
|
||||
LatestEpochWritten: 0,
|
||||
}
|
||||
dbAttestationHistory1 := make(map[[48]byte]*slashpb.AttestationHistory)
|
||||
dbAttestationHistory1[firstStorePubKey] = pubKeyAttestationHistory1
|
||||
if err := firstStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory1); err != nil {
|
||||
return nil, errors.Wrapf(err, "Saving attestation history failed")
|
||||
}
|
||||
attestationHistoryMap2 := make(map[uint64]uint64)
|
||||
attestationHistoryMap2[0] = 1
|
||||
pubKeyAttestationHistory2 := &slashpb.AttestationHistory{
|
||||
TargetToSource: attestationHistoryMap2,
|
||||
LatestEpochWritten: 0,
|
||||
}
|
||||
dbAttestationHistory2 := make(map[[48]byte]*slashpb.AttestationHistory)
|
||||
dbAttestationHistory2[secondStorePubKey] = pubKeyAttestationHistory2
|
||||
if err := secondStore.SaveAttestationHistoryForPubKeys(context.Background(), dbAttestationHistory2); err != nil {
|
||||
return nil, errors.Wrapf(err, "Saving attestation history failed")
|
||||
}
|
||||
|
||||
mergeHistory := &sourceStoresHistory{
|
||||
ProposalEpoch: proposalEpoch,
|
||||
FirstStorePubKeyProposals: proposalHistory1,
|
||||
SecondStorePubKeyProposals: proposalHistory2,
|
||||
FirstStorePubKeyAttestations: attestationHistoryMap1,
|
||||
SecondStorePubKeyAttestations: attestationHistoryMap2,
|
||||
}
|
||||
|
||||
return mergeHistory, nil
|
||||
}
|
||||
|
||||
func assertMergedStore(
|
||||
t *testing.T,
|
||||
mergedStore *kv.Store,
|
||||
firstStorePubKey, secondStorePubKey [48]byte,
|
||||
history *sourceStoresHistory) {
|
||||
|
||||
mergedProposalHistory1, err := mergedStore.ProposalHistoryForEpoch(
|
||||
context.Background(), firstStorePubKey[:], history.ProposalEpoch)
|
||||
require.NoError(t, err, "Retrieving merged proposal history failed for public key %v", firstStorePubKey)
|
||||
require.DeepEqual(t, history.FirstStorePubKeyProposals, mergedProposalHistory1, "Proposals not merged correctly")
|
||||
mergedProposalHistory2, err := mergedStore.ProposalHistoryForEpoch(
|
||||
context.Background(), secondStorePubKey[:], history.ProposalEpoch)
|
||||
require.NoError(t, err, "Retrieving merged proposal history failed for public key %v", secondStorePubKey)
|
||||
require.DeepEqual(t, history.SecondStorePubKeyProposals, mergedProposalHistory2, "Proposals not merged correctly")
|
||||
|
||||
mergedAttestationHistory, err := mergedStore.AttestationHistoryForPubKeys(
|
||||
context.Background(),
|
||||
[][48]byte{firstStorePubKey, secondStorePubKey})
|
||||
require.NoError(t, err, "Retrieving merged attestation history failed")
|
||||
assert.Equal(t, history.FirstStorePubKeyAttestations[0], mergedAttestationHistory[firstStorePubKey].TargetToSource[0])
|
||||
assert.Equal(t, history.SecondStorePubKeyAttestations[0], mergedAttestationHistory[secondStorePubKey].TargetToSource[0])
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// statusTimeout defines a period after which request to fetch account statuses is cancelled.
|
||||
const statusTimeout = 30 * time.Second
|
||||
|
||||
// ValidatorStatusMetadata holds all status information about a validator.
|
||||
type ValidatorStatusMetadata struct {
|
||||
PublicKey []byte
|
||||
Index uint64
|
||||
Metadata *ethpb.ValidatorStatusResponse
|
||||
}
|
||||
|
||||
// RunStatusCommand is the entry point to the `validator status` command.
|
||||
func RunStatusCommand(ctx context.Context, pubKeys [][]byte, beaconNodeRPCProvider ethpb.BeaconNodeValidatorClient) error {
|
||||
statuses, err := FetchAccountStatuses(ctx, beaconNodeRPCProvider, pubKeys)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch account statuses from the beacon node")
|
||||
}
|
||||
printStatuses(statuses)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchAccountStatuses fetches validator statuses from the BeaconNodeValidatorClient
|
||||
// for each validator public key.
|
||||
func FetchAccountStatuses(
|
||||
ctx context.Context,
|
||||
beaconClient ethpb.BeaconNodeValidatorClient,
|
||||
pubKeys [][]byte,
|
||||
) ([]ValidatorStatusMetadata, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "accounts.FetchAccountStatuses")
|
||||
defer span.End()
|
||||
ctx, cancel := context.WithTimeout(ctx, statusTimeout)
|
||||
defer cancel()
|
||||
|
||||
req := ðpb.MultipleValidatorStatusRequest{PublicKeys: pubKeys}
|
||||
resp, err := beaconClient.MultipleValidatorStatus(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statuses := make([]ValidatorStatusMetadata, len(resp.Statuses))
|
||||
for i, status := range resp.Statuses {
|
||||
statuses[i] = ValidatorStatusMetadata{
|
||||
PublicKey: resp.PublicKeys[i],
|
||||
Index: resp.Indices[i],
|
||||
Metadata: status,
|
||||
}
|
||||
}
|
||||
sort.Slice(statuses, func(i, j int) bool {
|
||||
return statuses[i].Metadata.Status < statuses[j].Metadata.Status
|
||||
})
|
||||
|
||||
return statuses, nil
|
||||
}
|
||||
|
||||
func printStatuses(validatorStatuses []ValidatorStatusMetadata) {
|
||||
nonexistentIndex := ^uint64(0)
|
||||
for _, v := range validatorStatuses {
|
||||
m := v.Metadata
|
||||
key := v.PublicKey
|
||||
fields := logrus.Fields{
|
||||
"publicKey": fmt.Sprintf("%#x", key),
|
||||
}
|
||||
if v.Index != nonexistentIndex {
|
||||
fields["index"] = v.Index
|
||||
}
|
||||
if m.Status == ethpb.ValidatorStatus_PENDING || m.Status == ethpb.ValidatorStatus_ACTIVE {
|
||||
fields["activationEpoch"] = m.ActivationEpoch
|
||||
if m.ActivationEpoch == params.BeaconConfig().FarFutureEpoch {
|
||||
fields["positionInActivationQueue"] = m.PositionInActivationQueue
|
||||
}
|
||||
} else if m.Status == ethpb.ValidatorStatus_DEPOSITED {
|
||||
if m.PositionInActivationQueue != 0 {
|
||||
fields["depositInclusionSlot"] = m.DepositInclusionSlot
|
||||
fields["eth1DepositBlockNumber"] = m.Eth1DepositBlockNumber
|
||||
} else {
|
||||
fields["positionInActivationQueue"] = m.PositionInActivationQueue
|
||||
}
|
||||
}
|
||||
log.WithFields(fields).Infof("Status: %s", m.Status.String())
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/mock"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFetchAccountStatuses_OK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
pubkeys := make([][]byte, 10000)
|
||||
indices := make([]uint64, 10000)
|
||||
for i := 0; i < 10000; i++ {
|
||||
pubkeys[i] = []byte{byte(i)}
|
||||
indices[i] = uint64(i)
|
||||
}
|
||||
|
||||
mockClient := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
mockClient.EXPECT().MultipleValidatorStatus(
|
||||
gomock.Any(),
|
||||
ðpb.MultipleValidatorStatusRequest{PublicKeys: pubkeys},
|
||||
).Return(ðpb.MultipleValidatorStatusResponse{PublicKeys: pubkeys, Indices: indices}, nil /*err*/)
|
||||
_, err := FetchAccountStatuses(ctx, mockClient, pubkeys)
|
||||
require.NoError(t, err, "FetchAccountStatuses failed with error")
|
||||
}
|
||||
@@ -24,9 +24,7 @@ this command outputs a deposit data string which is required to become a validat
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.AccountPasswordFileFlag,
|
||||
flags.NumAccountsFlag,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
featureconfig.AltonaTestnet,
|
||||
featureconfig.OnyxTestnet,
|
||||
featureconfig.MedallaTestnet,
|
||||
@@ -50,7 +48,6 @@ this command outputs a deposit data string which is required to become a validat
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.AccountPasswordFileFlag,
|
||||
flags.DeletePublicKeysFlag,
|
||||
featureconfig.AltonaTestnet,
|
||||
featureconfig.OnyxTestnet,
|
||||
@@ -81,7 +78,6 @@ this command outputs a deposit data string which is required to become a validat
|
||||
featureconfig.MedallaTestnet,
|
||||
featureconfig.SpadinaTestnet,
|
||||
featureconfig.ZinkenTestnet,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
@@ -137,7 +133,6 @@ this command outputs a deposit data string which is required to become a validat
|
||||
featureconfig.MedallaTestnet,
|
||||
featureconfig.SpadinaTestnet,
|
||||
featureconfig.ZinkenTestnet,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
|
||||
@@ -29,7 +29,6 @@ var WalletCommands = &cli.Command{
|
||||
featureconfig.MedallaTestnet,
|
||||
featureconfig.SpadinaTestnet,
|
||||
featureconfig.ZinkenTestnet,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
featureconfig.ConfigureValidator(cliCtx)
|
||||
@@ -53,7 +52,6 @@ var WalletCommands = &cli.Command{
|
||||
featureconfig.MedallaTestnet,
|
||||
featureconfig.SpadinaTestnet,
|
||||
featureconfig.ZinkenTestnet,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
featureconfig.ConfigureValidator(cliCtx)
|
||||
@@ -76,7 +74,6 @@ var WalletCommands = &cli.Command{
|
||||
featureconfig.MedallaTestnet,
|
||||
featureconfig.SpadinaTestnet,
|
||||
featureconfig.ZinkenTestnet,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
featureconfig.ConfigureValidator(cliCtx)
|
||||
|
||||
@@ -58,7 +58,6 @@ func setupWalletCtx(
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.WalletDirFlag.Name, cfg.walletDir, "")
|
||||
set.String(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir, "")
|
||||
set.String(flags.KeysDirFlag.Name, cfg.keysDir, "")
|
||||
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
|
||||
set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "")
|
||||
@@ -76,7 +75,6 @@ func setupWalletCtx(
|
||||
assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile))
|
||||
}
|
||||
assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
|
||||
assert.NoError(tb, set.Set(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir))
|
||||
assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir))
|
||||
assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
|
||||
assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys))
|
||||
|
||||
@@ -66,7 +66,6 @@ func setupWalletCtx(
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.WalletDirFlag.Name, cfg.walletDir, "")
|
||||
set.String(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir, "")
|
||||
set.String(flags.KeysDirFlag.Name, cfg.keysDir, "")
|
||||
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
|
||||
set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "")
|
||||
@@ -84,7 +83,6 @@ func setupWalletCtx(
|
||||
assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile))
|
||||
}
|
||||
assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
|
||||
assert.NoError(tb, set.Set(flags.DeprecatedPasswordsDirFlag.Name, cfg.passwordsDir))
|
||||
assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir))
|
||||
assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
|
||||
assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys))
|
||||
|
||||
@@ -35,12 +35,10 @@ go_library(
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//validator/accounts/v2/wallet:go_default_library",
|
||||
"//validator/db:go_default_library",
|
||||
"//validator/keymanager/v1:go_default_library",
|
||||
"//validator/keymanager/v2:go_default_library",
|
||||
"//validator/keymanager/v2/direct:go_default_library",
|
||||
"//validator/slashing-protection:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_ferranbt_fastssz//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_gogo_protobuf//types:go_default_library",
|
||||
"@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library",
|
||||
@@ -53,7 +51,6 @@ go_library(
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//plugin/ocgrpc:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
@@ -89,7 +86,6 @@ go_test(
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/keystore:go_default_library",
|
||||
"//shared/mock:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/slotutil:go_default_library",
|
||||
@@ -97,9 +93,7 @@ go_test(
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//validator/accounts/v1:go_default_library",
|
||||
"//validator/db/testing:go_default_library",
|
||||
"//validator/keymanager/v1:go_default_library",
|
||||
"//validator/testing:go_default_library",
|
||||
"@com_github_gogo_protobuf//types:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
|
||||
@@ -5,12 +5,10 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
@@ -116,25 +114,18 @@ func (v *validator) signSlot(ctx context.Context, pubKey [48]byte, slot uint64)
|
||||
}
|
||||
|
||||
var sig bls.Signature
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
root, err := helpers.ComputeSigningRoot(slot, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Slot{Slot: slot},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
sig, err = v.signObject(ctx, pubKey, slot, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to sign slot")
|
||||
}
|
||||
root, err := helpers.ComputeSigningRoot(slot, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Slot{Slot: slot},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sig.Marshal(), nil
|
||||
@@ -164,25 +155,18 @@ func (v *validator) aggregateAndProofSig(ctx context.Context, pubKey [48]byte, a
|
||||
return nil, err
|
||||
}
|
||||
var sig bls.Signature
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
root, err := helpers.ComputeSigningRoot(agg, d.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: d.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: agg},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
sig, err = v.signObject(ctx, pubKey, agg, d.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to sign slot")
|
||||
}
|
||||
root, err := helpers.ComputeSigningRoot(agg, d.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: d.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: agg},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sig.Marshal(), nil
|
||||
|
||||
@@ -19,22 +19,26 @@ import (
|
||||
|
||||
func TestSubmitAggregateAndProof_GetDutiesRequestFailure(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{}}
|
||||
defer finish()
|
||||
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, pubKey)
|
||||
|
||||
require.LogsContain(t, hook, "Could not fetch validator assignment")
|
||||
}
|
||||
|
||||
func TestSubmitAggregateAndProof_SignFails(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -68,16 +72,18 @@ func TestSubmitAggregateAndProof_SignFails(t *testing.T) {
|
||||
gomock.Any(), // epoch
|
||||
).Return(ðpb.DomainResponse{SignatureDomain: nil}, errors.New("bad domain root"))
|
||||
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey)
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, pubKey)
|
||||
}
|
||||
|
||||
func TestSubmitAggregateAndProof_Ok(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -116,11 +122,11 @@ func TestSubmitAggregateAndProof_Ok(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.SignedAggregateSubmitRequest{}),
|
||||
).Return(ðpb.SignedAggregateSubmitResponse{AttestationDataRoot: make([]byte, 32)}, nil)
|
||||
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, validatorPubKey)
|
||||
validator.SubmitAggregateAndProof(context.Background(), 0, pubKey)
|
||||
}
|
||||
|
||||
func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) {
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, _, finish := setup(t)
|
||||
defer finish()
|
||||
currentTime := timeutils.Now()
|
||||
numOfSlots := uint64(4)
|
||||
@@ -135,9 +141,11 @@ func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
ðpb.DomainRequest{Epoch: 0, Domain: params.BeaconConfig().DomainAggregateAndProof[:]},
|
||||
@@ -155,7 +163,7 @@ func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) {
|
||||
},
|
||||
SelectionProof: make([]byte, 96),
|
||||
}
|
||||
sig, err := validator.aggregateAndProofSig(context.Background(), validatorPubKey, agg)
|
||||
sig, err := validator.aggregateAndProofSig(context.Background(), pubKey, agg)
|
||||
require.NoError(t, err)
|
||||
_, err = bls.SignatureFromBytes(sig)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -11,14 +11,11 @@ import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -176,21 +173,12 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sig bls.Signature
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_AttestationData{AttestationData: data},
|
||||
})
|
||||
} else {
|
||||
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
|
||||
sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data)
|
||||
} else {
|
||||
sig, err = v.keyManager.Sign(ctx, pubKey, root)
|
||||
}
|
||||
}
|
||||
sig, err := v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_AttestationData{AttestationData: data},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ func TestPreSignatureValidation(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
Data: ðpb.AttestationData{
|
||||
@@ -40,10 +42,10 @@ func TestPreSignatureValidation(t *testing.T) {
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowAttestation: false}
|
||||
validator.protector = mockProtector
|
||||
err := validator.preAttSignValidations(context.Background(), att, validatorPubKey)
|
||||
err := validator.preAttSignValidations(context.Background(), att, pubKey)
|
||||
require.ErrorContains(t, failedPreAttSignExternalErr, err)
|
||||
mockProtector.AllowAttestation = true
|
||||
err = validator.preAttSignValidations(context.Background(), att, validatorPubKey)
|
||||
err = validator.preAttSignValidations(context.Background(), att, pubKey)
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
|
||||
@@ -54,7 +56,7 @@ func TestPreSignatureValidation_NilLocal(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, _, finish := setup(t)
|
||||
defer finish()
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
@@ -84,8 +86,10 @@ func TestPostSignatureUpdate(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
Data: ðpb.AttestationData{
|
||||
@@ -104,10 +108,10 @@ func TestPostSignatureUpdate(t *testing.T) {
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowAttestation: false}
|
||||
validator.protector = mockProtector
|
||||
err := validator.postAttSignUpdate(context.Background(), att, validatorPubKey)
|
||||
err := validator.postAttSignUpdate(context.Background(), att, pubKey)
|
||||
require.ErrorContains(t, failedPostAttSignExternalErr, err, "Expected error on post signature update is detected as slashable")
|
||||
mockProtector.AllowAttestation = true
|
||||
err = validator.postAttSignUpdate(context.Background(), att, validatorPubKey)
|
||||
err = validator.postAttSignUpdate(context.Background(), att, pubKey)
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
|
||||
@@ -118,7 +122,7 @@ func TestPostSignatureUpdate_NilLocal(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, _, finish := setup(t)
|
||||
defer finish()
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -23,38 +24,42 @@ import (
|
||||
|
||||
func TestRequestAttestation_ValidatorDutiesRequestFailure(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{}}
|
||||
defer finish()
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsContain(t, hook, "Could not fetch validator assignment")
|
||||
}
|
||||
|
||||
func TestAttestToBlockHead_SubmitAttestation_EmptyCommittee(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 0,
|
||||
Committee: make([]uint64, 0),
|
||||
ValidatorIndex: 0,
|
||||
}}}
|
||||
validator.SubmitAttestation(context.Background(), 0, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 0, pubKey)
|
||||
require.LogsContain(t, hook, "Empty committee")
|
||||
}
|
||||
|
||||
func TestAttestToBlockHead_SubmitAttestation_RequestFailure(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: make([]uint64, 111),
|
||||
ValidatorIndex: 0,
|
||||
@@ -76,7 +81,9 @@ func TestAttestToBlockHead_SubmitAttestation_RequestFailure(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.Attestation{}),
|
||||
).Return(nil, errors.New("something went wrong"))
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsContain(t, hook, "Could not submit attestation to beacon node")
|
||||
}
|
||||
|
||||
@@ -86,14 +93,16 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
hook := logTest.NewGlobal()
|
||||
validatorIndex := uint64(7)
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -125,7 +134,7 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) {
|
||||
generatedAttestation = att
|
||||
}).Return(ðpb.AttestResponse{}, nil /* error */)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
|
||||
aggregationBitfield := bitfield.NewBitlist(uint64(len(committee)))
|
||||
aggregationBitfield.SetBitAt(4, true)
|
||||
@@ -142,7 +151,10 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) {
|
||||
root, err := helpers.ComputeSigningRoot(expectedAttestation.Data, make([]byte, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
sig, err := validator.keyManager.Sign(context.Background(), validatorPubKey, root)
|
||||
sig, err := validator.keyManagerV2.Sign(context.Background(), &validatorpb.SignRequest{
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
SigningRoot: root[:],
|
||||
})
|
||||
require.NoError(t, err)
|
||||
expectedAttestation.Signature = sig.Marshal()
|
||||
if !reflect.DeepEqual(generatedAttestation, expectedAttestation) {
|
||||
@@ -160,13 +172,15 @@ func TestAttestToBlockHead_BlocksDoubleAtt(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validatorIndex := uint64(7)
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -194,8 +208,8 @@ func TestAttestToBlockHead_BlocksDoubleAtt(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.Attestation{}),
|
||||
).Return(ðpb.AttestResponse{AttestationDataRoot: make([]byte, 32)}, nil /* error */)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsContain(t, hook, failedPreAttSignLocalErr)
|
||||
}
|
||||
|
||||
@@ -206,13 +220,15 @@ func TestAttestToBlockHead_BlocksSurroundAtt(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validatorIndex := uint64(7)
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -241,8 +257,8 @@ func TestAttestToBlockHead_BlocksSurroundAtt(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.Attestation{}),
|
||||
).Return(ðpb.AttestResponse{}, nil /* error */)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsContain(t, hook, failedPreAttSignLocalErr)
|
||||
}
|
||||
|
||||
@@ -253,13 +269,15 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validatorIndex := uint64(7)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -288,7 +306,7 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.Attestation{}),
|
||||
).Return(ðpb.AttestResponse{}, nil /* error */)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreAttSignLocalErr)
|
||||
|
||||
m.validatorClient.EXPECT().GetAttestationData(
|
||||
@@ -300,14 +318,16 @@ func TestAttestToBlockHead_BlocksSurroundedAtt(t *testing.T) {
|
||||
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte("C"), 32), Epoch: 1},
|
||||
}, nil)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
require.LogsContain(t, hook, failedPreAttSignLocalErr)
|
||||
}
|
||||
|
||||
func TestAttestToBlockHead_DoesNotAttestBeforeDelay(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.genesisTime = uint64(timeutils.Now().Unix())
|
||||
m.validatorClient.EXPECT().GetDuties(
|
||||
gomock.Any(), // ctx
|
||||
@@ -326,12 +346,12 @@ func TestAttestToBlockHead_DoesNotAttestBeforeDelay(t *testing.T) {
|
||||
).Return(ðpb.AttestResponse{}, nil /* error */).Times(0)
|
||||
|
||||
timer := time.NewTimer(1 * time.Second)
|
||||
go validator.SubmitAttestation(context.Background(), 0, validatorPubKey)
|
||||
go validator.SubmitAttestation(context.Background(), 0, pubKey)
|
||||
<-timer.C
|
||||
}
|
||||
|
||||
func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
@@ -341,9 +361,11 @@ func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) {
|
||||
validator.genesisTime = uint64(timeutils.Now().Unix())
|
||||
validatorIndex := uint64(5)
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -370,17 +392,19 @@ func TestAttestToBlockHead_DoesAttestAfterDelay(t *testing.T) {
|
||||
gomock.Any(),
|
||||
).Return(ðpb.AttestResponse{}, nil).Times(1)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 0, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 0, pubKey)
|
||||
}
|
||||
|
||||
func TestAttestToBlockHead_CorrectBitfieldLength(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validatorIndex := uint64(2)
|
||||
committee := []uint64{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.duties = ðpb.DutiesResponse{Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
PublicKey: validatorKey.PublicKey.Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
CommitteeIndex: 5,
|
||||
Committee: committee,
|
||||
ValidatorIndex: validatorIndex,
|
||||
@@ -407,7 +431,7 @@ func TestAttestToBlockHead_CorrectBitfieldLength(t *testing.T) {
|
||||
generatedAttestation = att
|
||||
}).Return(ðpb.AttestResponse{}, nil /* error */)
|
||||
|
||||
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
|
||||
validator.SubmitAttestation(context.Background(), 30, pubKey)
|
||||
|
||||
assert.Equal(t, 2, len(generatedAttestation.AggregationBits))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -133,11 +132,7 @@ func (v *validator) LogValidatorGainsAndLosses(ctx context.Context, slot uint64)
|
||||
|
||||
var pks [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
pks, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
pks, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
pks, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,10 +12,8 @@ import (
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
km "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -175,27 +173,19 @@ func (v *validator) signRandaoReveal(ctx context.Context, pubKey [48]byte, epoch
|
||||
}
|
||||
|
||||
var randaoReveal bls.Signature
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
root, err := helpers.ComputeSigningRoot(epoch, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
randaoReveal, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Epoch{Epoch: epoch},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
randaoReveal, err = v.signObject(ctx, pubKey, epoch, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign reveal")
|
||||
}
|
||||
root, err := helpers.ComputeSigningRoot(epoch, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
randaoReveal, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: root[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Epoch{Epoch: epoch},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return randaoReveal.Marshal(), nil
|
||||
}
|
||||
|
||||
@@ -210,47 +200,18 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64
|
||||
}
|
||||
|
||||
var sig bls.Signature
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, signingRootErr)
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: blockRoot[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Block{Block: b},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign block proposal")
|
||||
}
|
||||
return sig.Marshal(), nil
|
||||
blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, signingRootErr)
|
||||
}
|
||||
if protectingKeymanager, supported := v.keyManager.(km.ProtectingKeyManager); supported {
|
||||
bodyRoot, err := b.Body.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, signingRootErr)
|
||||
}
|
||||
blockHeader := ðpb.BeaconBlockHeader{
|
||||
Slot: b.Slot,
|
||||
ProposerIndex: b.ProposerIndex,
|
||||
StateRoot: b.StateRoot,
|
||||
ParentRoot: b.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
sig, err = protectingKeymanager.SignProposal(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), blockHeader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign block proposal")
|
||||
}
|
||||
} else {
|
||||
blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, signingRootErr)
|
||||
}
|
||||
sig, err = v.keyManager.Sign(ctx, pubKey, blockRoot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign block proposal")
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
SigningRoot: blockRoot[:],
|
||||
SignatureDomain: domain.SignatureDomain,
|
||||
Object: &validatorpb.SignRequest_Block{Block: b},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign block proposal")
|
||||
}
|
||||
return sig.Marshal(), nil
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ func TestPreBlockSignValidation(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Slot: 10,
|
||||
@@ -26,10 +28,10 @@ func TestPreBlockSignValidation(t *testing.T) {
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
|
||||
validator.protector = mockProtector
|
||||
err := validator.preBlockSignValidations(context.Background(), validatorPubKey, block)
|
||||
err := validator.preBlockSignValidations(context.Background(), pubKey, block)
|
||||
require.ErrorContains(t, failedPreBlockSignExternalErr, err)
|
||||
mockProtector.AllowBlock = true
|
||||
err = validator.preBlockSignValidations(context.Background(), validatorPubKey, block)
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKey, block)
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
|
||||
@@ -40,8 +42,10 @@ func TestPostBlockSignUpdate(t *testing.T) {
|
||||
}
|
||||
reset := featureconfig.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
@@ -51,9 +55,9 @@ func TestPostBlockSignUpdate(t *testing.T) {
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
|
||||
validator.protector = mockProtector
|
||||
err := validator.postBlockSignUpdate(context.Background(), validatorPubKey, block)
|
||||
err := validator.postBlockSignUpdate(context.Background(), pubKey, block)
|
||||
require.ErrorContains(t, failedPostBlockSignErr, err, "Expected error when post signature update is detected as slashable")
|
||||
mockProtector.AllowBlock = true
|
||||
err = validator.postBlockSignUpdate(context.Background(), validatorPubKey, block)
|
||||
err = validator.postBlockSignUpdate(context.Background(), pubKey, block)
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
|
||||
@@ -47,8 +47,11 @@ func (m mockSignature) Copy() bls.Signature {
|
||||
return m
|
||||
}
|
||||
|
||||
func setup(t *testing.T) (*validator, *mocks, func()) {
|
||||
valDB := testing2.SetupDB(t, [][48]byte{validatorPubKey})
|
||||
func setup(t *testing.T) (*validator, *mocks, bls.SecretKey, func()) {
|
||||
validatorKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
valDB := testing2.SetupDB(t, [][48]byte{pubKey})
|
||||
ctrl := gomock.NewController(t)
|
||||
m := &mocks{
|
||||
validatorClient: mock.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
@@ -66,62 +69,75 @@ func setup(t *testing.T) (*validator, *mocks, func()) {
|
||||
TargetToSource: cleanMap,
|
||||
}
|
||||
attHistoryByPubKey := make(map[[48]byte]*slashpb.AttestationHistory)
|
||||
attHistoryByPubKey[validatorPubKey] = clean
|
||||
|
||||
attHistoryByPubKey[pubKey] = clean
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: validatorKey,
|
||||
},
|
||||
}
|
||||
validator := &validator{
|
||||
db: valDB,
|
||||
keyManagerV2: km,
|
||||
validatorClient: m.validatorClient,
|
||||
keyManager: testKeyManager,
|
||||
graffiti: []byte{},
|
||||
attLogs: make(map[[32]byte]*attSubmitted),
|
||||
aggregatedSlotCommitteeIDCache: aggregatedSlotCommitteeIDCache,
|
||||
attesterHistoryByPubKey: attHistoryByPubKey,
|
||||
}
|
||||
|
||||
return validator, m, ctrl.Finish
|
||||
return validator, m, validatorKey, ctrl.Finish
|
||||
}
|
||||
|
||||
func TestProposeBlock_DoesNotProposeGenesisBlock(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, _, finish := setup(t)
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
validator.ProposeBlock(context.Background(), 0, validatorPubKey)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
validator.ProposeBlock(context.Background(), 0, pubKey)
|
||||
|
||||
require.LogsContain(t, hook, "Assigned to genesis slot, skipping proposal")
|
||||
}
|
||||
|
||||
func TestProposeBlock_DomainDataFailed(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(nil /*response*/, errors.New("uh oh"))
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
require.LogsContain(t, hook, "Failed to sign randao reveal")
|
||||
}
|
||||
|
||||
func TestProposeBlock_DomainDataIsNil(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(nil /*response*/, nil)
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
require.LogsContain(t, hook, domainDataErr)
|
||||
}
|
||||
|
||||
func TestProposeBlock_RequestBlockFailed(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -133,14 +149,16 @@ func TestProposeBlock_RequestBlockFailed(t *testing.T) {
|
||||
gomock.Any(), // block request
|
||||
).Return(nil /*response*/, errors.New("uh oh"))
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
require.LogsContain(t, hook, "Failed to request block from beacon node")
|
||||
}
|
||||
|
||||
func TestProposeBlock_ProposeBlockFailed(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -162,7 +180,7 @@ func TestProposeBlock_ProposeBlockFailed(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}),
|
||||
).Return(nil /*response*/, errors.New("uh oh"))
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
require.LogsContain(t, hook, "Failed to propose block")
|
||||
}
|
||||
|
||||
@@ -173,8 +191,10 @@ func TestProposeBlock_BlocksDoubleProposal(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(cfg)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -197,10 +217,10 @@ func TestProposeBlock_BlocksDoubleProposal(t *testing.T) {
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
slot := params.BeaconConfig().SlotsPerEpoch*5 + 2
|
||||
validator.ProposeBlock(context.Background(), slot, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
|
||||
validator.ProposeBlock(context.Background(), slot, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsContain(t, hook, failedPreBlockSignLocalErr)
|
||||
}
|
||||
|
||||
@@ -211,8 +231,10 @@ func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(cfg)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -235,10 +257,10 @@ func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) {
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
farFuture := (params.BeaconConfig().WeakSubjectivityPeriod + 9) * params.BeaconConfig().SlotsPerEpoch
|
||||
validator.ProposeBlock(context.Background(), farFuture, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), farFuture, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farFuture, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), farFuture, pubKey)
|
||||
require.LogsContain(t, hook, failedPreBlockSignLocalErr)
|
||||
}
|
||||
|
||||
@@ -249,8 +271,10 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(cfg)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -275,7 +299,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}),
|
||||
).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farAhead, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), farAhead, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
|
||||
past := (params.BeaconConfig().WeakSubjectivityPeriod - 400) * params.BeaconConfig().SlotsPerEpoch
|
||||
@@ -285,7 +309,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(),
|
||||
).Return(blk2.Block, nil /*err*/)
|
||||
validator.ProposeBlock(context.Background(), past, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), past, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
}
|
||||
|
||||
@@ -296,8 +320,10 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
reset := featureconfig.InitWithReset(cfg)
|
||||
defer reset()
|
||||
hook := logTest.NewGlobal()
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -322,7 +348,6 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}),
|
||||
).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
pubKey := validatorPubKey
|
||||
validator.ProposeBlock(context.Background(), farAhead, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
|
||||
@@ -338,8 +363,10 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProposeBlock_BroadcastsBlock(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
@@ -361,12 +388,14 @@ func TestProposeBlock_BroadcastsBlock(t *testing.T) {
|
||||
gomock.AssignableToTypeOf(ðpb.SignedBeaconBlock{}),
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
}
|
||||
|
||||
func TestProposeBlock_BroadcastsBlock_WithGraffiti(t *testing.T) {
|
||||
validator, m, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
validator.graffiti = []byte("12345678901234567890123456789012")
|
||||
|
||||
@@ -397,12 +426,12 @@ func TestProposeBlock_BroadcastsBlock_WithGraffiti(t *testing.T) {
|
||||
return ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil
|
||||
})
|
||||
|
||||
validator.ProposeBlock(context.Background(), 1, validatorPubKey)
|
||||
validator.ProposeBlock(context.Background(), 1, pubKey)
|
||||
assert.Equal(t, string(validator.graffiti), string(sentBlock.Block.Body.Graffiti))
|
||||
}
|
||||
|
||||
func TestProposeExit_ValidatorIndexFailed(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().ValidatorIndex(
|
||||
@@ -410,14 +439,20 @@ func TestProposeExit_ValidatorIndexFailed(t *testing.T) {
|
||||
gomock.Any(),
|
||||
).Return(nil, errors.New("uh oh"))
|
||||
|
||||
err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])
|
||||
err := ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
assert.ErrorContains(t, "uh oh", err)
|
||||
assert.ErrorContains(t, "gRPC call to get validator index failed", err)
|
||||
}
|
||||
|
||||
func TestProposeExit_GetGenesisFailed(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
@@ -428,14 +463,20 @@ func TestProposeExit_GetGenesisFailed(t *testing.T) {
|
||||
GetGenesis(gomock.Any(), gomock.Any()).
|
||||
Return(nil, errors.New("uh oh"))
|
||||
|
||||
err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])
|
||||
err := ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
assert.ErrorContains(t, "uh oh", err)
|
||||
assert.ErrorContains(t, "gRPC call to get genesis time failed", err)
|
||||
}
|
||||
|
||||
func TestProposeExit_DomainDataFailed(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
@@ -455,7 +496,13 @@ func TestProposeExit_DomainDataFailed(t *testing.T) {
|
||||
DomainData(gomock.Any(), gomock.Any()).
|
||||
Return(nil, errors.New("uh oh"))
|
||||
|
||||
err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])
|
||||
err := ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
assert.ErrorContains(t, domainDataErr, err)
|
||||
assert.ErrorContains(t, "uh oh", err)
|
||||
@@ -463,7 +510,7 @@ func TestProposeExit_DomainDataFailed(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProposeExit_DomainDataIsNil(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
@@ -483,14 +530,20 @@ func TestProposeExit_DomainDataIsNil(t *testing.T) {
|
||||
DomainData(gomock.Any(), gomock.Any()).
|
||||
Return(nil, nil)
|
||||
|
||||
err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])
|
||||
err := ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
assert.ErrorContains(t, domainDataErr, err)
|
||||
assert.ErrorContains(t, "failed to sign voluntary exit", err)
|
||||
}
|
||||
|
||||
func TestProposeBlock_ProposeExitFailed(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
@@ -514,14 +567,20 @@ func TestProposeBlock_ProposeExitFailed(t *testing.T) {
|
||||
ProposeExit(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedVoluntaryExit{})).
|
||||
Return(nil, errors.New("uh oh"))
|
||||
|
||||
err := ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:])
|
||||
err := ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
assert.ErrorContains(t, "uh oh", err)
|
||||
assert.ErrorContains(t, "failed to propose voluntary exit", err)
|
||||
}
|
||||
|
||||
func TestProposeExit_BroadcastsBlock(t *testing.T) {
|
||||
_, m, finish := setup(t)
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
@@ -545,5 +604,11 @@ func TestProposeExit_BroadcastsBlock(t *testing.T) {
|
||||
ProposeExit(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedVoluntaryExit{})).
|
||||
Return(ðpb.ProposeExitResponse{}, nil)
|
||||
|
||||
assert.NoError(t, ProposeExit(context.Background(), m.validatorClient, m.nodeClient, m.signExitFunc, validatorPubKey[:]))
|
||||
assert.NoError(t, ProposeExit(
|
||||
context.Background(),
|
||||
m.validatorClient,
|
||||
m.nodeClient,
|
||||
m.signExitFunc,
|
||||
validatorKey.PublicKey().Marshal(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
fssz "github.com/ferranbt/fastssz"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
|
||||
@@ -16,17 +15,12 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/grpcutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
|
||||
"github.com/prysmaticlabs/prysm/validator/db"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
@@ -64,7 +58,6 @@ type ValidatorService struct {
|
||||
walletInitializedFeed *event.Feed
|
||||
cancel context.CancelFunc
|
||||
db db.Database
|
||||
keyManager keymanager.KeyManager
|
||||
dataDir string
|
||||
withCert string
|
||||
endpoint string
|
||||
@@ -90,7 +83,6 @@ type Config struct {
|
||||
Validator Validator
|
||||
ValDB db.Database
|
||||
KeyManagerV2 v2.IKeymanager
|
||||
KeyManager keymanager.KeyManager
|
||||
GraffitiFlag string
|
||||
CertFlag string
|
||||
DataDir string
|
||||
@@ -108,7 +100,6 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e
|
||||
withCert: cfg.CertFlag,
|
||||
dataDir: cfg.DataDir,
|
||||
graffiti: []byte(cfg.GraffitiFlag),
|
||||
keyManager: cfg.KeyManager,
|
||||
keyManagerV2: cfg.KeyManagerV2,
|
||||
logValidatorBalances: cfg.LogValidatorBalances,
|
||||
emitAccountMetrics: cfg.EmitAccountMetrics,
|
||||
@@ -173,7 +164,6 @@ func (v *ValidatorService) Start() {
|
||||
validatorClient: ethpb.NewBeaconNodeValidatorClient(v.conn),
|
||||
beaconClient: ethpb.NewBeaconChainClient(v.conn),
|
||||
node: ethpb.NewNodeClient(v.conn),
|
||||
keyManager: v.keyManager,
|
||||
keyManagerV2: v.keyManagerV2,
|
||||
graffiti: v.graffiti,
|
||||
logValidatorBalances: v.logValidatorBalances,
|
||||
@@ -213,40 +203,30 @@ func (v *ValidatorService) Status() error {
|
||||
func (v *ValidatorService) recheckKeys(ctx context.Context) {
|
||||
var validatingKeys [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
if v.useWeb {
|
||||
initializedChan := make(chan *wallet.Wallet)
|
||||
sub := v.walletInitializedFeed.Subscribe(initializedChan)
|
||||
cleanup := sub.Unsubscribe
|
||||
defer cleanup()
|
||||
w := <-initializedChan
|
||||
keyManagerV2, err := w.InitializeKeymanager(
|
||||
ctx, true, /* skipMnemonicConfirm */
|
||||
)
|
||||
if err != nil {
|
||||
// log.Fatalf will prevent defer from being called
|
||||
cleanup()
|
||||
log.Fatalf("Could not read keymanager for wallet: %v", err)
|
||||
}
|
||||
v.keyManagerV2 = keyManagerV2
|
||||
}
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
if v.useWeb {
|
||||
initializedChan := make(chan *wallet.Wallet)
|
||||
sub := v.walletInitializedFeed.Subscribe(initializedChan)
|
||||
cleanup := sub.Unsubscribe
|
||||
defer cleanup()
|
||||
w := <-initializedChan
|
||||
keyManagerV2, err := w.InitializeKeymanager(
|
||||
ctx, true, /* skipMnemonicConfirm */
|
||||
)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not fetch validating keys")
|
||||
}
|
||||
if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil {
|
||||
log.WithError(err).Debug("Could not update public keys buckets")
|
||||
}
|
||||
go recheckValidatingKeysBucket(ctx, v.db, v.keyManagerV2)
|
||||
} else {
|
||||
validatingKeys, err = v.keyManager.FetchValidatingKeys()
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not fetch validating keys")
|
||||
}
|
||||
if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil {
|
||||
log.WithError(err).Debug("Could not update public keys buckets")
|
||||
// log.Fatalf will prevent defer from being called
|
||||
cleanup()
|
||||
log.Fatalf("Could not read keymanager for wallet: %v", err)
|
||||
}
|
||||
v.keyManagerV2 = keyManagerV2
|
||||
}
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not fetch validating keys")
|
||||
}
|
||||
if err := v.db.UpdatePublicKeysBuckets(validatingKeys); err != nil {
|
||||
log.WithError(err).Debug("Could not update public keys buckets")
|
||||
}
|
||||
go recheckValidatingKeysBucket(ctx, v.db, v.keyManagerV2)
|
||||
for _, key := range validatingKeys {
|
||||
log.WithField(
|
||||
"publicKey", fmt.Sprintf("%#x", bytesutil.Trunc(key[:])),
|
||||
@@ -254,40 +234,6 @@ func (v *ValidatorService) recheckKeys(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// signObject signs a generic object, with protection if available.
|
||||
// This should only be used for accounts v1.
|
||||
func (v *validator) signObject(
|
||||
ctx context.Context,
|
||||
pubKey [48]byte,
|
||||
object interface{},
|
||||
domain []byte,
|
||||
) (bls.Signature, error) {
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
return nil, errors.New("signObject not supported for accounts v2")
|
||||
}
|
||||
|
||||
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
|
||||
var root [32]byte
|
||||
var err error
|
||||
if v, ok := object.(fssz.HashRoot); ok {
|
||||
root, err = v.HashTreeRoot()
|
||||
} else {
|
||||
root, err = ssz.HashTreeRoot(object)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return protectingKeymanager.SignGeneric(pubKey, root, bytesutil.ToBytes32(domain))
|
||||
}
|
||||
|
||||
root, err := helpers.ComputeSigningRoot(object, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.keyManager.Sign(ctx, pubKey, root)
|
||||
}
|
||||
|
||||
// ConstructDialOptions constructs a list of grpc dial options
|
||||
func ConstructDialOptions(
|
||||
maxCallRecvMsgSize int,
|
||||
|
||||
@@ -7,53 +7,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/keystore"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
var _ shared.Service = (*ValidatorService)(nil)
|
||||
var validatorKey *keystore.Key
|
||||
var validatorPubKey [48]byte
|
||||
var keyMap map[[48]byte]*keystore.Key
|
||||
var keyMapThreeValidators map[[48]byte]*keystore.Key
|
||||
var testKeyManager keymanager.KeyManager
|
||||
var testKeyManagerThreeValidators keymanager.KeyManager
|
||||
|
||||
func keySetup() {
|
||||
keyMap = make(map[[48]byte]*keystore.Key)
|
||||
keyMapThreeValidators = make(map[[48]byte]*keystore.Key)
|
||||
|
||||
var err error
|
||||
validatorKey, err = keystore.NewKey()
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Cannot create key")
|
||||
}
|
||||
copy(validatorPubKey[:], validatorKey.PublicKey.Marshal())
|
||||
keyMap[validatorPubKey] = validatorKey
|
||||
|
||||
sks := make([]bls.SecretKey, 1)
|
||||
sks[0] = validatorKey.SecretKey
|
||||
testKeyManager = keymanager.NewDirect(sks)
|
||||
|
||||
sks = make([]bls.SecretKey, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
vKey, err := keystore.NewKey()
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Cannot create key")
|
||||
}
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], vKey.PublicKey.Marshal())
|
||||
keyMapThreeValidators[pubKey] = vKey
|
||||
sks[i] = vKey.SecretKey
|
||||
}
|
||||
testKeyManagerThreeValidators = keymanager.NewDirect(sks)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dir := testutil.TempDir() + "/keystore1"
|
||||
@@ -63,10 +23,6 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
}
|
||||
defer cleanup()
|
||||
if err := v1.NewValidatorAccount(dir, "1234"); err != nil {
|
||||
log.WithError(err).Debug("Cannot create validator account")
|
||||
}
|
||||
keySetup()
|
||||
code := m.Run()
|
||||
// os.Exit will prevent defer from being called
|
||||
cleanup()
|
||||
@@ -95,11 +51,10 @@ func TestLifecycle(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
validatorService := &ValidatorService{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
endpoint: "merkle tries",
|
||||
withCert: "alice.crt",
|
||||
keyManager: keymanager.NewDirect(nil),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
endpoint: "merkle tries",
|
||||
withCert: "alice.crt",
|
||||
}
|
||||
validatorService.Start()
|
||||
require.NoError(t, validatorService.Stop(), "Could not stop service")
|
||||
@@ -112,10 +67,9 @@ func TestLifecycle_Insecure(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
validatorService := &ValidatorService{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
endpoint: "merkle tries",
|
||||
keyManager: keymanager.NewDirect(nil),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
endpoint: "merkle tries",
|
||||
}
|
||||
validatorService.Start()
|
||||
require.LogsContain(t, hook, "You are using an insecure gRPC connection")
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
|
||||
vdb "github.com/prysmaticlabs/prysm/validator/db"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -69,7 +68,6 @@ type validator struct {
|
||||
duties *ethpb.DutiesResponse
|
||||
startBalances map[[48]byte]uint64
|
||||
attLogs map[[32]byte]*attSubmitted
|
||||
keyManager keymanager.KeyManager
|
||||
node ethpb.NodeClient
|
||||
keyManagerV2 v2keymanager.IKeymanager
|
||||
beaconClient ethpb.BeaconChainClient
|
||||
@@ -243,13 +241,7 @@ func (v *validator) WaitForActivation(ctx context.Context) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.WaitForActivation")
|
||||
defer span.End()
|
||||
|
||||
var validatingKeys [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
validatingKeys, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
validatingKeys, err := v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch validating keys")
|
||||
}
|
||||
@@ -389,12 +381,7 @@ func (v *validator) UpdateDuties(ctx context.Context, slot uint64) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.UpdateAssignments")
|
||||
defer span.End()
|
||||
|
||||
var validatingKeys [][48]byte
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
validatingKeys, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
validatingKeys, err := v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/golang/mock/gomock"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
slashpb "github.com/prysmaticlabs/prysm/proto/slashing"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mock"
|
||||
@@ -18,7 +20,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
dbTest "github.com/prysmaticlabs/prysm/validator/db/testing"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
@@ -32,14 +33,30 @@ var _ Validator = (*validator)(nil)
|
||||
|
||||
const cancelledCtx = "context has been canceled"
|
||||
|
||||
func publicKeys(t *testing.T, km keymanager.KeyManager) [][]byte {
|
||||
keys, err := km.FetchValidatingKeys()
|
||||
assert.NoError(t, err, "Cannot fetch validating keys")
|
||||
res := make([][]byte, len(keys))
|
||||
for i := range keys {
|
||||
res[i] = keys[i][:]
|
||||
type mockKeymanager struct {
|
||||
lock sync.RWMutex
|
||||
keysMap map[[48]byte]bls.SecretKey
|
||||
}
|
||||
|
||||
func (m *mockKeymanager) FetchValidatingPublicKeys(ctx context.Context) ([][48]byte, error) {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
keys := make([][48]byte, 0)
|
||||
for pubKey := range m.keysMap {
|
||||
keys = append(keys, pubKey)
|
||||
}
|
||||
return res
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (m *mockKeymanager) Sign(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) {
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], req.PublicKey)
|
||||
privKey, ok := m.keysMap[pubKey]
|
||||
if !ok {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
sig := privKey.Sign(req.SigningRoot)
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
func generateMockStatusResponse(pubkeys [][]byte) *ethpb.ValidatorActivationResponse {
|
||||
@@ -61,7 +78,7 @@ func TestWaitForChainStart_SetsChainStartGenesisTime(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
//keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
genesis := uint64(time.Unix(1, 0).Unix())
|
||||
@@ -88,7 +105,7 @@ func TestWaitForChainStart_ContextCanceled(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
//keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
genesis := uint64(time.Unix(0, 0).Unix())
|
||||
@@ -114,9 +131,15 @@ func TestWaitForChainStart_StreamSetupFails(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: make(map[[48]byte]bls.SecretKey),
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForChainStartClient(ctrl)
|
||||
client.EXPECT().WaitForChainStart(
|
||||
@@ -134,7 +157,7 @@ func TestWaitForChainStart_ReceiveErrorFromStream(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
//keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForChainStartClient(ctrl)
|
||||
@@ -157,7 +180,7 @@ func TestWaitForSynced_SetsGenesisTime(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
//keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
genesis := uint64(time.Unix(1, 0).Unix())
|
||||
@@ -184,7 +207,6 @@ func TestWaitForSynced_ContextCanceled(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
genesis := uint64(time.Unix(0, 0).Unix())
|
||||
@@ -211,7 +233,6 @@ func TestWaitForSynced_StreamSetupFails(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForSyncedClient(ctrl)
|
||||
@@ -230,7 +251,6 @@ func TestWaitForSynced_ReceiveErrorFromStream(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForSyncedClient(ctrl)
|
||||
@@ -251,17 +271,24 @@ func TestWaitActivation_ContextCanceled(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
|
||||
client.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
ðpb.ValidatorActivationRequest{
|
||||
PublicKeys: publicKeys(t, v.keyManager),
|
||||
PublicKeys: [][]byte{pubKey[:]},
|
||||
},
|
||||
).Return(clientStream, nil)
|
||||
clientStream.EXPECT().Recv().Return(
|
||||
@@ -277,16 +304,23 @@ func TestWaitActivation_StreamSetupFails(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
client.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
ðpb.ValidatorActivationRequest{
|
||||
PublicKeys: publicKeys(t, v.keyManager),
|
||||
PublicKeys: [][]byte{pubKey[:]},
|
||||
},
|
||||
).Return(clientStream, errors.New("failed stream"))
|
||||
err := v.WaitForActivation(context.Background())
|
||||
@@ -299,15 +333,23 @@ func TestWaitActivation_ReceiveErrorFromStream(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
}
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
client.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
ðpb.ValidatorActivationRequest{
|
||||
PublicKeys: publicKeys(t, v.keyManager),
|
||||
PublicKeys: [][]byte{pubKey[:]},
|
||||
},
|
||||
).Return(clientStream, nil)
|
||||
clientStream.EXPECT().Recv().Return(
|
||||
@@ -324,19 +366,26 @@ func TestWaitActivation_LogsActivationEpochOK(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
genesisTime: 1,
|
||||
}
|
||||
resp := generateMockStatusResponse(publicKeys(t, v.keyManager))
|
||||
resp := generateMockStatusResponse([][]byte{pubKey[:]})
|
||||
resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
client.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
ðpb.ValidatorActivationRequest{
|
||||
PublicKeys: publicKeys(t, v.keyManager),
|
||||
PublicKeys: [][]byte{pubKey[:]},
|
||||
},
|
||||
).Return(clientStream, nil)
|
||||
clientStream.EXPECT().Recv().Return(
|
||||
@@ -352,7 +401,6 @@ func TestCanonicalHeadSlot_FailedRPC(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconChainClient(ctrl)
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
beaconClient: client,
|
||||
genesisTime: 1,
|
||||
}
|
||||
@@ -369,7 +417,6 @@ func TestCanonicalHeadSlot_OK(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconChainClient(ctrl)
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
beaconClient: client,
|
||||
}
|
||||
client.EXPECT().GetChainHead(
|
||||
@@ -386,21 +433,27 @@ func TestWaitMultipleActivation_LogsActivationEpochOK(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManagerThreeValidators,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
genesisTime: 1,
|
||||
}
|
||||
publicKeys := publicKeys(t, v.keyManager)
|
||||
resp := generateMockStatusResponse(publicKeys)
|
||||
|
||||
resp := generateMockStatusResponse([][]byte{pubKey[:]})
|
||||
resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE
|
||||
resp.Statuses[1].Status.Status = ethpb.ValidatorStatus_ACTIVE
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
client.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
ðpb.ValidatorActivationRequest{
|
||||
PublicKeys: publicKeys,
|
||||
PublicKeys: [][]byte{pubKey[:]},
|
||||
},
|
||||
).Return(clientStream, nil)
|
||||
clientStream.EXPECT().Recv().Return(
|
||||
@@ -416,12 +469,20 @@ func TestWaitActivation_NotAllValidatorsActivatedOK(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManagerThreeValidators,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
genesisTime: 1,
|
||||
}
|
||||
resp := generateMockStatusResponse(publicKeys(t, v.keyManager))
|
||||
resp := generateMockStatusResponse([][]byte{pubKey[:]})
|
||||
resp.Statuses[0].Status.Status = ethpb.ValidatorStatus_ACTIVE
|
||||
clientStream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
client.EXPECT().WaitForActivation(
|
||||
@@ -505,7 +566,6 @@ func TestUpdateDuties_DoesNothingWhenNotEpochStart_AlreadyExistingAssignments(t
|
||||
|
||||
slot := uint64(1)
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
duties: ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
@@ -530,9 +590,17 @@ func TestUpdateDuties_ReturnsError(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
keyManagerV2: km,
|
||||
duties: ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
@@ -559,6 +627,14 @@ func TestUpdateDuties_OK(t *testing.T) {
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
|
||||
slot := params.BeaconConfig().SlotsPerEpoch
|
||||
privKey := bls.RandKey()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], privKey.PublicKey().Marshal())
|
||||
km := &mockKeymanager{
|
||||
keysMap: map[[48]byte]bls.SecretKey{
|
||||
pubKey: privKey,
|
||||
},
|
||||
}
|
||||
resp := ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
@@ -572,7 +648,7 @@ func TestUpdateDuties_OK(t *testing.T) {
|
||||
},
|
||||
}
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
keyManagerV2: km,
|
||||
validatorClient: client,
|
||||
}
|
||||
client.EXPECT().GetDuties(
|
||||
@@ -650,7 +726,6 @@ func TestUpdateProtections_OK(t *testing.T) {
|
||||
}
|
||||
v := validator{
|
||||
db: db,
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
duties: duties,
|
||||
}
|
||||
@@ -672,7 +747,6 @@ func TestSaveProtections_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
v := validator{
|
||||
db: db,
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
attesterHistoryByPubKey: cleanHistories,
|
||||
}
|
||||
@@ -695,37 +769,15 @@ func TestSaveProtections_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRolesAt_OK(t *testing.T) {
|
||||
v, m, finish := setup(t)
|
||||
v, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
sks := make([]bls.SecretKey, 4)
|
||||
sks[0] = bls.RandKey()
|
||||
sks[1] = bls.RandKey()
|
||||
sks[2] = bls.RandKey()
|
||||
sks[3] = bls.RandKey()
|
||||
v.keyManager = keymanager.NewDirect(sks)
|
||||
v.duties = ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
CommitteeIndex: 1,
|
||||
AttesterSlot: 1,
|
||||
PublicKey: sks[0].PublicKey().Marshal(),
|
||||
},
|
||||
{
|
||||
CommitteeIndex: 2,
|
||||
ProposerSlots: []uint64{1},
|
||||
PublicKey: sks[1].PublicKey().Marshal(),
|
||||
},
|
||||
{
|
||||
CommitteeIndex: 1,
|
||||
AttesterSlot: 2,
|
||||
PublicKey: sks[2].PublicKey().Marshal(),
|
||||
},
|
||||
{
|
||||
CommitteeIndex: 2,
|
||||
AttesterSlot: 1,
|
||||
ProposerSlots: []uint64{1, 5},
|
||||
PublicKey: sks[3].PublicKey().Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -735,50 +787,23 @@ func TestRolesAt_OK(t *testing.T) {
|
||||
gomock.Any(), // epoch
|
||||
).Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
|
||||
|
||||
roleMap, err := v.RolesAt(context.Background(), 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[0].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleProposer), roleMap[bytesutil.ToBytes48(sks[1].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[2].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleProposer), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][1])
|
||||
assert.Equal(t, ValidatorRole(roleAggregator), roleMap[bytesutil.ToBytes48(sks[3].PublicKey().Marshal())][2])
|
||||
assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())][0])
|
||||
}
|
||||
|
||||
func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) {
|
||||
v, m, finish := setup(t)
|
||||
v, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
sks := make([]bls.SecretKey, 3)
|
||||
sks[0] = bls.RandKey()
|
||||
sks[1] = bls.RandKey()
|
||||
sks[2] = bls.RandKey()
|
||||
v.keyManager = keymanager.NewDirect(sks)
|
||||
v.duties = ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
{
|
||||
CommitteeIndex: 1,
|
||||
AttesterSlot: 0,
|
||||
ProposerSlots: []uint64{0},
|
||||
PublicKey: sks[0].PublicKey().Marshal(),
|
||||
},
|
||||
{
|
||||
CommitteeIndex: 2,
|
||||
AttesterSlot: 4,
|
||||
ProposerSlots: nil,
|
||||
PublicKey: sks[1].PublicKey().Marshal(),
|
||||
},
|
||||
{
|
||||
CommitteeIndex: 1,
|
||||
AttesterSlot: 3,
|
||||
ProposerSlots: nil,
|
||||
PublicKey: sks[2].PublicKey().Marshal(),
|
||||
PublicKey: validatorKey.PublicKey().Marshal(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -791,9 +816,7 @@ func TestRolesAt_DoesNotAssignProposer_Slot0(t *testing.T) {
|
||||
roleMap, err := v.RolesAt(context.Background(), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(sks[0].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[1].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleUnknown), roleMap[bytesutil.ToBytes48(sks[2].PublicKey().Marshal())][0])
|
||||
assert.Equal(t, ValidatorRole(roleAttester), roleMap[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())][0])
|
||||
}
|
||||
|
||||
func TestCheckAndLogValidatorStatus_OK(t *testing.T) {
|
||||
@@ -891,7 +914,6 @@ func TestCheckAndLogValidatorStatus_OK(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
client := mock.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
v := validator{
|
||||
keyManager: testKeyManager,
|
||||
validatorClient: client,
|
||||
duties: ðpb.DutiesResponse{
|
||||
Duties: []*ethpb.DutiesResponse_Duty{
|
||||
|
||||
@@ -10,7 +10,6 @@ go_library(
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//shared/fileutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/fileutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -17,8 +16,6 @@ const (
|
||||
WalletDefaultDirName = "prysm-wallet-v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "flags")
|
||||
|
||||
var (
|
||||
// DisableAccountMetricsFlag defines the graffiti value included in proposed blocks, default false.
|
||||
DisableAccountMetricsFlag = &cli.BoolFlag{
|
||||
@@ -120,56 +117,12 @@ var (
|
||||
"(browser enforced). This flag has no effect if not used with --grpc-gateway-port.",
|
||||
Value: "http://localhost:4242,http://127.0.0.1:4242,http://localhost:4200",
|
||||
}
|
||||
// KeyManager specifies the key manager to use.
|
||||
KeyManager = &cli.StringFlag{
|
||||
Name: "keymanager",
|
||||
Usage: "The keymanger to use (unencrypted, interop, keystore, wallet)",
|
||||
Value: "",
|
||||
}
|
||||
// KeyManagerOpts specifies the key manager options.
|
||||
KeyManagerOpts = &cli.StringFlag{
|
||||
Name: "keymanageropts",
|
||||
Usage: "The options for the keymanger, either a JSON string or path to same",
|
||||
Value: "",
|
||||
}
|
||||
// KeystorePathFlag defines the location of the keystore directory for a validator's account.
|
||||
KeystorePathFlag = &cli.StringFlag{
|
||||
Name: "keystore-path",
|
||||
Usage: "Path to the desired keystore directory",
|
||||
}
|
||||
// MonitoringPortFlag defines the http port used to serve prometheus metrics.
|
||||
MonitoringPortFlag = &cli.IntFlag{
|
||||
Name: "monitoring-port",
|
||||
Usage: "Port used to listening and respond metrics for prometheus.",
|
||||
Value: 8081,
|
||||
}
|
||||
// PasswordFlag defines the password value for storing and retrieving validator private keys from the keystore.
|
||||
PasswordFlag = &cli.StringFlag{
|
||||
Name: "password",
|
||||
Usage: "String value of the password for your validator private keys",
|
||||
}
|
||||
// SourceDirectories defines the locations of the source validator databases while managing validators.
|
||||
SourceDirectories = &cli.StringFlag{
|
||||
Name: "source-dirs",
|
||||
Usage: "The directory of source validator databases",
|
||||
}
|
||||
// SourceDirectory defines the location of the source validator database while managing validators.
|
||||
SourceDirectory = &cli.StringFlag{
|
||||
Name: "source-dir",
|
||||
Usage: "The directory of the source validator database",
|
||||
}
|
||||
// TargetDirectory defines the location of the target validator database while managing validators.
|
||||
TargetDirectory = &cli.StringFlag{
|
||||
Name: "target-dir",
|
||||
Usage: "The directory of the target validator database",
|
||||
}
|
||||
// UnencryptedKeysFlag specifies a file path of a JSON file of unencrypted validator keys as an
|
||||
// alternative from launching the validator client from decrypting a keystore directory.
|
||||
UnencryptedKeysFlag = &cli.StringFlag{
|
||||
Name: "unencrypted-keys",
|
||||
Usage: "Filepath to a JSON file of unencrypted validator keys for easier launching of the validator client",
|
||||
Value: "",
|
||||
}
|
||||
// WalletDirFlag defines the path to a wallet directory for Prysm accounts-v2.
|
||||
WalletDirFlag = &cli.StringFlag{
|
||||
Name: "wallet-dir",
|
||||
@@ -306,32 +259,6 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Deprecated flags list.
|
||||
const deprecatedUsage = "DEPRECATED. DO NOT USE."
|
||||
|
||||
var (
|
||||
// DeprecatedPasswordsDirFlag is a deprecated flag.
|
||||
DeprecatedPasswordsDirFlag = &cli.StringFlag{
|
||||
Name: "passwords-dir",
|
||||
Usage: deprecatedUsage,
|
||||
Hidden: true,
|
||||
}
|
||||
)
|
||||
|
||||
// DeprecatedFlags is a slice holding all of the validator client's deprecated flags.
|
||||
var DeprecatedFlags = []cli.Flag{
|
||||
DeprecatedPasswordsDirFlag,
|
||||
}
|
||||
|
||||
// ComplainOnDeprecatedFlags logs out a error log if a deprecated flag is used, letting the user know it will be removed soon.
|
||||
func ComplainOnDeprecatedFlags(ctx *cli.Context) {
|
||||
for _, f := range DeprecatedFlags {
|
||||
if ctx.IsSet(f.Names()[0]) {
|
||||
log.Errorf("%s is deprecated and has no effect. Do not use this flag, it will be deleted soon.", f.Names()[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultValidatorDir returns OS-specific default validator directory.
|
||||
func DefaultValidatorDir() string {
|
||||
// Try to place the data folder in the user's home dir
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"direct.go",
|
||||
"direct_interop.go",
|
||||
"direct_keystore.go",
|
||||
"direct_unencrypted.go",
|
||||
"keymanager.go",
|
||||
"log.go",
|
||||
"opts.go",
|
||||
"remote.go",
|
||||
"wallet.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/validator/keymanager/v1",
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/interop:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//validator/accounts/v1:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_wealdtech_eth2_signer_api//pb/v1:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_store_filesystem//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_types_v2//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//credentials:go_default_library",
|
||||
"@org_golang_x_crypto//ssh/terminal:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"direct_interop_test.go",
|
||||
"direct_test.go",
|
||||
"opts_test.go",
|
||||
"remote_internal_test.go",
|
||||
"remote_test.go",
|
||||
"wallet_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_nd_v2//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_store_filesystem//:go_default_library",
|
||||
"@com_github_wealdtech_go_eth2_wallet_types_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,48 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
)
|
||||
|
||||
// Direct is a key manager that holds all secret keys directly.
|
||||
type Direct struct {
|
||||
// Key to the map is the bytes of the public key.
|
||||
publicKeys map[[48]byte]bls.PublicKey
|
||||
// Key to the map is the bytes of the public key.
|
||||
secretKeys map[[48]byte]bls.SecretKey
|
||||
}
|
||||
|
||||
// NewDirect creates a new direct key manager from the secret keys provided to it.
|
||||
func NewDirect(sks []bls.SecretKey) *Direct {
|
||||
res := &Direct{
|
||||
publicKeys: make(map[[48]byte]bls.PublicKey),
|
||||
secretKeys: make(map[[48]byte]bls.SecretKey),
|
||||
}
|
||||
for _, sk := range sks {
|
||||
publicKey := sk.PublicKey()
|
||||
pubKey := bytesutil.ToBytes48(publicKey.Marshal())
|
||||
res.publicKeys[pubKey] = publicKey
|
||||
res.secretKeys[pubKey] = sk
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// FetchValidatingKeys fetches the list of public keys that should be used to validate with.
|
||||
func (km *Direct) FetchValidatingKeys() ([][48]byte, error) {
|
||||
keys := make([][48]byte, 0, len(km.publicKeys))
|
||||
for key := range km.publicKeys {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// Sign signs a message for the validator to broadcast.
|
||||
func (km *Direct) Sign(_ context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error) {
|
||||
if secretKey, exists := km.secretKeys[pubKey]; exists {
|
||||
return secretKey.Sign(root[:]), nil
|
||||
}
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/interop"
|
||||
)
|
||||
|
||||
// Interop is a key manager that deterministically generates keys.
|
||||
type Interop struct {
|
||||
*Direct
|
||||
}
|
||||
|
||||
type interopOpts struct {
|
||||
Keys uint64 `json:"keys"`
|
||||
Offset uint64 `json:"offset"`
|
||||
}
|
||||
|
||||
var interopOptsHelp = `The interop key manager generates keys according to the interop testnet specification. The options are:
|
||||
- keys This is the number of keys to generate
|
||||
- offset This is the number of keys to skip before starting to generate keys
|
||||
A sample set of options are:
|
||||
{
|
||||
"keys": 5, // Generate 5 keys
|
||||
"offset": 1024 // Start with the 1024th key
|
||||
}`
|
||||
|
||||
// NewInterop creates a key manager using a number of interop keys at a given offset.
|
||||
func NewInterop(input string) (*Interop, string, error) {
|
||||
opts := &interopOpts{}
|
||||
err := json.Unmarshal([]byte(input), opts)
|
||||
if err != nil {
|
||||
return nil, interopOptsHelp, err
|
||||
}
|
||||
|
||||
sks, pks, err := interop.DeterministicallyGenerateKeys(opts.Offset, opts.Keys)
|
||||
if err != nil {
|
||||
return nil, interopOptsHelp, err
|
||||
}
|
||||
|
||||
km := &Interop{
|
||||
Direct: &Direct{
|
||||
publicKeys: make(map[[48]byte]bls.PublicKey),
|
||||
secretKeys: make(map[[48]byte]bls.SecretKey),
|
||||
},
|
||||
}
|
||||
for i := 0; uint64(i) < opts.Keys; i++ {
|
||||
pubKey := bytesutil.ToBytes48(pks[i].Marshal())
|
||||
km.publicKeys[pubKey] = pks[i]
|
||||
km.secretKeys[pubKey] = sks[i]
|
||||
}
|
||||
return km, "", nil
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
)
|
||||
|
||||
func TestInteropListValidatingKeysZero(t *testing.T) {
|
||||
_, _, err := keymanager.NewInterop("")
|
||||
assert.ErrorContains(t, "unexpected end of JSON input", err)
|
||||
}
|
||||
|
||||
func TestInteropListValidatingKeysEmptyJSON(t *testing.T) {
|
||||
_, _, err := keymanager.NewInterop("{}")
|
||||
assert.ErrorContains(t, "input length must be greater than 0", err)
|
||||
}
|
||||
|
||||
func TestInteropListValidatingKeysSingle(t *testing.T) {
|
||||
direct, _, err := keymanager.NewInterop(`{"keys":1}`)
|
||||
require.NoError(t, err)
|
||||
keys, err := direct.FetchValidatingKeys()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(keys), "Incorrect number of keys returned")
|
||||
|
||||
pkBytes, err := hex.DecodeString("25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866")
|
||||
require.NoError(t, err)
|
||||
privateKey, err := bls.SecretKeyFromBytes(pkBytes)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, privateKey.PublicKey().Marshal(), keys[0][:], "Public k 0 incorrect")
|
||||
}
|
||||
|
||||
func TestInteropListValidatingKeysOffset(t *testing.T) {
|
||||
direct, _, err := keymanager.NewInterop(`{"keys":1,"offset":9}`)
|
||||
require.NoError(t, err)
|
||||
keys, err := direct.FetchValidatingKeys()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(keys), "Incorrect number of keys returned")
|
||||
|
||||
pkBytes, err := hex.DecodeString("2b3b88a041168a1c4cd04bdd8de7964fd35238f95442dc678514f9dadb81ec34")
|
||||
require.NoError(t, err)
|
||||
privateKey, err := bls.SecretKeyFromBytes(pkBytes)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, privateKey.PublicKey().Marshal(), keys[0][:], "Public k 0 incorrect")
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// Keystore is a key manager that loads keys from a standard keystore.
|
||||
type Keystore struct {
|
||||
*Direct
|
||||
}
|
||||
|
||||
type keystoreOpts struct {
|
||||
Path string `json:"path"`
|
||||
Passphrase string `json:"passphrase"`
|
||||
}
|
||||
|
||||
var keystoreOptsHelp = `The keystore key manager generates keys and stores them in a local encrypted store. The options are:
|
||||
- path This is the filesystem path to where keys will be stored. Defaults to the user's home directory if not supplied
|
||||
- passphrase This is the passphrase used to encrypt keys. Will be asked for if not supplied
|
||||
A sample set of options are:
|
||||
{
|
||||
"path": "/home/me/keys", // Store the keys in '/home/me/keys'
|
||||
"passphrase": "secret" // Use the passphrase 'secret' to encrypt and decrypt keys
|
||||
}`
|
||||
|
||||
// NewKeystore creates a key manager populated with the keys from the keystore at the given path.
|
||||
func NewKeystore(input string) (KeyManager, string, error) {
|
||||
opts := &keystoreOpts{}
|
||||
err := json.Unmarshal([]byte(input), opts)
|
||||
if err != nil {
|
||||
return nil, keystoreOptsHelp, err
|
||||
}
|
||||
|
||||
if strings.Contains(opts.Path, "$") || strings.Contains(opts.Path, "~") || strings.Contains(opts.Path, "%") {
|
||||
log.WithField("path", opts.Path).Warn("Keystore path contains unexpanded shell expansion characters")
|
||||
}
|
||||
|
||||
if opts.Path == "" {
|
||||
opts.Path = v1.DefaultValidatorDir()
|
||||
}
|
||||
log.WithField("keystorePath", opts.Path).Debug("Checking validator keys")
|
||||
|
||||
exists, err := v1.Exists(opts.Path, true /* assertNonEmpty */)
|
||||
if err != nil {
|
||||
return nil, keystoreOptsHelp, err
|
||||
}
|
||||
if exists {
|
||||
if opts.Passphrase == "" {
|
||||
log.Info("Enter your validator account password:")
|
||||
bytePassword, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
return nil, keystoreOptsHelp, err
|
||||
}
|
||||
text := string(bytePassword)
|
||||
opts.Passphrase = strings.ReplaceAll(text, "\n", "")
|
||||
}
|
||||
|
||||
if err := v1.VerifyAccountNotExists(opts.Path, opts.Passphrase); err == nil {
|
||||
log.Info("No account found, creating new validator account...")
|
||||
}
|
||||
} else {
|
||||
return nil, "", errors.New("no validator keys found, please use validator accounts create")
|
||||
}
|
||||
|
||||
keyMap, err := v1.DecryptKeysFromKeystore(opts.Path, params.BeaconConfig().ValidatorPrivkeyFileName, opts.Passphrase)
|
||||
if err != nil {
|
||||
return nil, keystoreOptsHelp, err
|
||||
}
|
||||
|
||||
km := &Unencrypted{
|
||||
Direct: &Direct{
|
||||
publicKeys: make(map[[48]byte]bls.PublicKey),
|
||||
secretKeys: make(map[[48]byte]bls.SecretKey),
|
||||
},
|
||||
}
|
||||
for _, key := range keyMap {
|
||||
pubKey := bytesutil.ToBytes48(key.PublicKey.Marshal())
|
||||
km.publicKeys[pubKey] = key.PublicKey
|
||||
km.secretKeys[pubKey] = key.SecretKey
|
||||
}
|
||||
return km, "", nil
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
)
|
||||
|
||||
func TestDirectListValidatingKeysNil(t *testing.T) {
|
||||
direct := keymanager.NewDirect(nil)
|
||||
keys, err := direct.FetchValidatingKeys()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(keys), "Incorrect number of keys returned")
|
||||
}
|
||||
|
||||
func TestDirectListValidatingKeysSingle(t *testing.T) {
|
||||
sks := make([]bls.SecretKey, 0)
|
||||
sks = append(sks, bls.RandKey())
|
||||
direct := keymanager.NewDirect(sks)
|
||||
keys, err := direct.FetchValidatingKeys()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(keys), "Incorrect number of keys returned")
|
||||
}
|
||||
|
||||
func TestDirectListValidatingKeysMultiple(t *testing.T) {
|
||||
sks := make([]bls.SecretKey, 0)
|
||||
numKeys := 256
|
||||
for i := 0; i < numKeys; i++ {
|
||||
sks = append(sks, bls.RandKey())
|
||||
}
|
||||
direct := keymanager.NewDirect(sks)
|
||||
keys, err := direct.FetchValidatingKeys()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, numKeys, len(keys), "Incorrect number of keys returned")
|
||||
}
|
||||
|
||||
func TestSignNoSuchKey(t *testing.T) {
|
||||
sks := make([]bls.SecretKey, 0)
|
||||
direct := keymanager.NewDirect(sks)
|
||||
_, err := direct.Sign(context.Background(), [48]byte{}, [32]byte{})
|
||||
assert.ErrorContains(t, keymanager.ErrNoSuchKey.Error(), err)
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
sks := make([]bls.SecretKey, 0)
|
||||
sks = append(sks, bls.RandKey())
|
||||
direct := keymanager.NewDirect(sks)
|
||||
|
||||
pubKey := bytesutil.ToBytes48(sks[0].PublicKey().Marshal())
|
||||
msg := [32]byte{}
|
||||
sig, err := direct.Sign(context.Background(), pubKey, msg)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, sig.Verify(sks[0].PublicKey(), bytesutil.FromBytes32(msg)), "Failed to verify generated signature")
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
)
|
||||
|
||||
// Unencrypted is a key manager that loads keys from an unencrypted store.
|
||||
type Unencrypted struct {
|
||||
*Direct
|
||||
}
|
||||
|
||||
type unencryptedOpts struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
var unencryptedOptsHelp = `The unencrypted key manager stores keys in a local unencrypted store. The options are:
|
||||
- path This is the filesystem path to a file containing the unencrypted keys
|
||||
A sample set of options are:
|
||||
{
|
||||
"path": "/home/me/keys.json" // Access the keys in '/home/me/keys.json'
|
||||
}`
|
||||
|
||||
// NewUnencrypted creates a keymanager from a file of unencrypted keys.
|
||||
func NewUnencrypted(input string) (*Unencrypted, string, error) {
|
||||
opts := &unencryptedOpts{}
|
||||
err := json.Unmarshal([]byte(input), opts)
|
||||
if err != nil {
|
||||
return nil, unencryptedOptsHelp, err
|
||||
}
|
||||
|
||||
if strings.Contains(opts.Path, "$") || strings.Contains(opts.Path, "~") || strings.Contains(opts.Path, "%") {
|
||||
log.WithField("path", opts.Path).Warn("Keystore path contains unexpanded shell expansion characters")
|
||||
}
|
||||
|
||||
path, err := filepath.Abs(opts.Path)
|
||||
if err != nil {
|
||||
return nil, unencryptedOptsHelp, err
|
||||
}
|
||||
reader, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, unencryptedOptsHelp, err
|
||||
}
|
||||
defer func() {
|
||||
if err := reader.Close(); err != nil {
|
||||
log.WithError(err).Error("Failed to close file reader")
|
||||
}
|
||||
}()
|
||||
|
||||
keyMap, err := unencryptedKeysFromReader(reader)
|
||||
if err != nil {
|
||||
return nil, unencryptedOptsHelp, err
|
||||
}
|
||||
sks := make([]bls.SecretKey, 0, len(keyMap))
|
||||
sks = append(sks, keyMap...)
|
||||
|
||||
km := &Unencrypted{
|
||||
Direct: &Direct{
|
||||
publicKeys: make(map[[48]byte]bls.PublicKey),
|
||||
secretKeys: make(map[[48]byte]bls.SecretKey),
|
||||
},
|
||||
}
|
||||
for i := 0; i < len(sks); i++ {
|
||||
pk := sks[i].PublicKey()
|
||||
pubKey := bytesutil.ToBytes48(pk.Marshal())
|
||||
km.publicKeys[pubKey] = pk
|
||||
km.secretKeys[pubKey] = sks[i]
|
||||
}
|
||||
return km, "", nil
|
||||
}
|
||||
|
||||
type unencryptedKeysContainer struct {
|
||||
Keys []*unencryptedKeys `json:"keys"`
|
||||
}
|
||||
|
||||
type unencryptedKeys struct {
|
||||
ValidatorKey []byte `json:"validator_key"`
|
||||
}
|
||||
|
||||
// unencryptedKeysFromReader loads the unencrypted keys from the given reader.
|
||||
func unencryptedKeysFromReader(reader io.Reader) ([]bls.SecretKey, error) {
|
||||
log.Warn("Loading encrypted keys from disk. Do not do this in production!")
|
||||
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ctnr *unencryptedKeysContainer
|
||||
if err := json.Unmarshal(data, &ctnr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]bls.SecretKey, 0, len(ctnr.Keys))
|
||||
for i := range ctnr.Keys {
|
||||
secretKey, err := bls.SecretKeyFromBytes(ctnr.Keys[i].ValidatorKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, secretKey)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
)
|
||||
|
||||
// ErrNoSuchKey is returned whenever a request is made for a key of which a key manager is unaware.
|
||||
var ErrNoSuchKey = errors.New("no such key")
|
||||
|
||||
// ErrCannotSign is returned whenever a signing attempt fails.
|
||||
var ErrCannotSign = errors.New("cannot sign")
|
||||
|
||||
// ErrDenied is returned whenever a signing attempt is denied.
|
||||
var ErrDenied = errors.New("signing attempt denied")
|
||||
|
||||
// KeyManager controls access to private keys by the validator.
|
||||
type KeyManager interface {
|
||||
// FetchValidatingKeys fetches the list of public keys that should be used to validate with.
|
||||
FetchValidatingKeys() ([][48]byte, error)
|
||||
// Sign signs a message for the validator to broadcast.
|
||||
// Note that the domain should already be part of the root, but it is passed along for security purposes.
|
||||
Sign(ctx context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error)
|
||||
}
|
||||
|
||||
// ProtectingKeyManager provides access to a keymanager that protects its clients from slashing events.
|
||||
type ProtectingKeyManager interface {
|
||||
// SignGeneric signs a generic root.
|
||||
// Note that the domain should already be part of the root, but it is provided for authorisation purposes.
|
||||
SignGeneric(pubKey [48]byte, root [32]byte, domain [32]byte) (bls.Signature, error)
|
||||
|
||||
// SignProposal signs a block proposal for the validator to broadcast.
|
||||
SignProposal(pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error)
|
||||
|
||||
// SignAttestation signs an attestation for the validator to broadcast.
|
||||
SignAttestation(pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "keymanager")
|
||||
@@ -1,32 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// decodeOpts decodes a value in to an options container.
|
||||
// The input can be either JSON data or a path to a file containing JSON.
|
||||
// This function returns an error if there is a problem decoding the input.
|
||||
func decodeOpts(input string, res interface{}) error {
|
||||
if input == "" {
|
||||
// Empty input is okay.
|
||||
return nil
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if strings.HasPrefix(input, "{") {
|
||||
// Looks like straight JSON.
|
||||
data = []byte(input)
|
||||
} else {
|
||||
// Assume it's a path.
|
||||
file, err := ioutil.ReadFile(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = file
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, res)
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestDecodeOpts(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
res interface{}
|
||||
err error
|
||||
result string
|
||||
}{
|
||||
{
|
||||
name: "EmptyInput",
|
||||
input: "",
|
||||
res: &struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}{},
|
||||
result: `{}`,
|
||||
},
|
||||
{
|
||||
name: "EmptyJSON",
|
||||
input: "{}",
|
||||
res: &struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}{},
|
||||
result: `{}`,
|
||||
},
|
||||
{
|
||||
name: "BadInput",
|
||||
input: "bad",
|
||||
res: &struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}{},
|
||||
err: errors.New("open bad: no such file or directory"),
|
||||
},
|
||||
{
|
||||
name: "GoodDirect",
|
||||
input: `{"name":"test"}`,
|
||||
res: &struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}{},
|
||||
result: `{"name":"test"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := decodeOpts(test.input, test.res)
|
||||
if test.err == nil {
|
||||
require.NoError(t, err)
|
||||
recoded, err := json.Marshal(test.res)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, []byte(test.result), recoded, "Unexpected recoded value")
|
||||
} else {
|
||||
assert.ErrorContains(t, test.err.Error(), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxMessageSize is the largest message that can be received over GRPC. Set to 8MB, which handles ~128K keys.
|
||||
maxMessageSize = 8 * 1024 * 1024
|
||||
)
|
||||
|
||||
// Remote is a key manager that accesses a remote wallet daemon.
|
||||
type Remote struct {
|
||||
paths []string
|
||||
conn *grpc.ClientConn
|
||||
accounts map[[48]byte]*accountInfo
|
||||
signClientInitiator func(*grpc.ClientConn)
|
||||
}
|
||||
|
||||
type accountInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey []byte `json:"pubkey"`
|
||||
}
|
||||
|
||||
type remoteOpts struct {
|
||||
Location string `json:"location"`
|
||||
Accounts []string `json:"accounts"`
|
||||
Certificates *remoteCertificateOpts `json:"certificates"`
|
||||
}
|
||||
|
||||
type remoteCertificateOpts struct {
|
||||
CACert string `json:"ca_cert"`
|
||||
ClientCert string `json:"client_cert"`
|
||||
ClientKey string `json:"client_key"`
|
||||
}
|
||||
|
||||
var remoteOptsHelp = `The remote key manager connects to a walletd instance. The options are:
|
||||
- location This is the location to look for wallets. If not supplied it will
|
||||
use the standard (operating system-dependent) path.
|
||||
- accounts This is a list of account specifiers. An account specifier is of
|
||||
the form <wallet name>/[account name], where the account name can be a
|
||||
regular expression. If the account specifier is just <wallet name> all
|
||||
accounts in that wallet will be used. Multiple account specifiers can be
|
||||
supplied if required.
|
||||
- certificates This provides paths to certificates:
|
||||
- ca_cert This is the path to the server's certificate authority certificate file
|
||||
- client_cert This is the path to the client's certificate file
|
||||
- client_key This is the path to the client's key file
|
||||
|
||||
An sample keymanager options file (with annotations; these should be removed if
|
||||
using this as a template) is:
|
||||
|
||||
{
|
||||
"location": "host.example.com:12345", // Connect to walletd at host.example.com on port 12345
|
||||
"accounts": ["Validators/Account.*"] // Use all accounts in the 'Validators' wallet starting with 'Account'
|
||||
"certificates": {
|
||||
"ca_cert": "/home/eth2/certs/ca.crt" // Certificate file for the CA that signed the server's certificate
|
||||
"client_cert": "/home/eth2/certs/client.crt" // Certificate file for this client
|
||||
"client_key": "/home/eth2/certs/client.key" // Key file for this client
|
||||
}
|
||||
}`
|
||||
|
||||
// NewRemoteWallet creates a key manager populated with the keys from walletd.
|
||||
func NewRemoteWallet(input string) (KeyManager, string, error) {
|
||||
opts := &remoteOpts{}
|
||||
err := json.Unmarshal([]byte(input), opts)
|
||||
if err != nil {
|
||||
return nil, remoteOptsHelp, err
|
||||
}
|
||||
|
||||
if len(opts.Accounts) == 0 {
|
||||
return nil, remoteOptsHelp, errors.New("at least one account specifier is required")
|
||||
}
|
||||
|
||||
// Load the client certificates.
|
||||
if opts.Certificates == nil {
|
||||
return nil, remoteOptsHelp, errors.New("certificates are required")
|
||||
}
|
||||
if opts.Certificates.ClientCert == "" {
|
||||
return nil, remoteOptsHelp, errors.New("client certificate is required")
|
||||
}
|
||||
if opts.Certificates.ClientKey == "" {
|
||||
return nil, remoteOptsHelp, errors.New("client key is required")
|
||||
}
|
||||
clientPair, err := tls.LoadX509KeyPair(opts.Certificates.ClientCert, opts.Certificates.ClientKey)
|
||||
if err != nil {
|
||||
return nil, remoteOptsHelp, errors.Wrap(err, "failed to obtain client's certificate and/or key")
|
||||
}
|
||||
|
||||
// Load the CA for the server certificate if present.
|
||||
cp := x509.NewCertPool()
|
||||
if opts.Certificates.CACert != "" {
|
||||
serverCA, err := ioutil.ReadFile(opts.Certificates.CACert)
|
||||
if err != nil {
|
||||
return nil, remoteOptsHelp, errors.Wrap(err, "failed to obtain server's CA certificate")
|
||||
}
|
||||
if !cp.AppendCertsFromPEM(serverCA) {
|
||||
return nil, remoteOptsHelp, errors.Wrap(err, "failed to add server's CA certificate to pool")
|
||||
}
|
||||
}
|
||||
|
||||
tlsCfg := &tls.Config{
|
||||
Certificates: []tls.Certificate{clientPair},
|
||||
RootCAs: cp,
|
||||
}
|
||||
clientCreds := credentials.NewTLS(tlsCfg)
|
||||
|
||||
grpcOpts := []grpc.DialOption{
|
||||
// Require TLS with client certificate.
|
||||
grpc.WithTransportCredentials(clientCreds),
|
||||
// Receive large messages without erroring.
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize)),
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(opts.Location, grpcOpts...)
|
||||
if err != nil {
|
||||
return nil, remoteOptsHelp, errors.New("failed to connect to remote wallet")
|
||||
}
|
||||
|
||||
km := &Remote{
|
||||
conn: conn,
|
||||
paths: opts.Accounts,
|
||||
}
|
||||
|
||||
err = km.RefreshValidatingKeys()
|
||||
if err != nil {
|
||||
return nil, remoteOptsHelp, errors.Wrap(err, "failed to fetch accounts from remote wallet")
|
||||
}
|
||||
|
||||
return km, remoteOptsHelp, nil
|
||||
}
|
||||
|
||||
// FetchValidatingKeys fetches the list of public keys that should be used to validate with.
|
||||
func (km *Remote) FetchValidatingKeys() ([][48]byte, error) {
|
||||
res := make([][48]byte, 0, len(km.accounts))
|
||||
for _, accountInfo := range km.accounts {
|
||||
res = append(res, bytesutil.ToBytes48(accountInfo.PubKey))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Sign without protection is not supported by remote keymanagers.
|
||||
func (km *Remote) Sign(_ context.Context, _ [48]byte, _ [32]byte) (bls.Signature, error) {
|
||||
return nil, errors.New("remote keymanager does not support unprotected signing")
|
||||
}
|
||||
|
||||
// SignGeneric signs a generic message for the validator to broadcast.
|
||||
func (km *Remote) SignGeneric(ctx context.Context, pubKey [48]byte, root, domain [32]byte) (bls.Signature, error) {
|
||||
accountInfo, exists := km.accounts[pubKey]
|
||||
if !exists {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
|
||||
client := pb.NewSignerClient(km.conn)
|
||||
req := &pb.SignRequest{
|
||||
Id: &pb.SignRequest_Account{Account: accountInfo.Name},
|
||||
Data: root[:],
|
||||
Domain: domain[:],
|
||||
}
|
||||
resp, err := client.Sign(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch resp.State {
|
||||
case pb.ResponseState_DENIED:
|
||||
return nil, ErrDenied
|
||||
case pb.ResponseState_FAILED:
|
||||
return nil, ErrCannotSign
|
||||
}
|
||||
return bls.SignatureFromBytes(resp.Signature)
|
||||
}
|
||||
|
||||
// SignProposal signs a block proposal for the validator to broadcast.
|
||||
func (km *Remote) SignProposal(ctx context.Context, pubKey [48]byte, domain [32]byte, data *ethpb.BeaconBlockHeader) (bls.Signature, error) {
|
||||
accountInfo, exists := km.accounts[pubKey]
|
||||
if !exists {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
|
||||
client := pb.NewSignerClient(km.conn)
|
||||
req := &pb.SignBeaconProposalRequest{
|
||||
Id: &pb.SignBeaconProposalRequest_Account{Account: accountInfo.Name},
|
||||
Domain: domain[:],
|
||||
Data: &pb.BeaconBlockHeader{
|
||||
Slot: data.Slot,
|
||||
ProposerIndex: data.ProposerIndex,
|
||||
ParentRoot: data.ParentRoot,
|
||||
StateRoot: data.StateRoot,
|
||||
BodyRoot: data.BodyRoot,
|
||||
},
|
||||
}
|
||||
resp, err := client.SignBeaconProposal(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch resp.State {
|
||||
case pb.ResponseState_DENIED:
|
||||
return nil, ErrDenied
|
||||
case pb.ResponseState_FAILED:
|
||||
return nil, ErrCannotSign
|
||||
}
|
||||
return bls.SignatureFromBytes(resp.Signature)
|
||||
}
|
||||
|
||||
// SignAttestation signs an attestation for the validator to broadcast.
|
||||
func (km *Remote) SignAttestation(ctx context.Context, pubKey [48]byte, domain [32]byte, data *ethpb.AttestationData) (bls.Signature, error) {
|
||||
accountInfo, exists := km.accounts[pubKey]
|
||||
if !exists {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
|
||||
client := pb.NewSignerClient(km.conn)
|
||||
req := &pb.SignBeaconAttestationRequest{
|
||||
Id: &pb.SignBeaconAttestationRequest_Account{Account: accountInfo.Name},
|
||||
Domain: domain[:],
|
||||
Data: &pb.AttestationData{
|
||||
Slot: data.Slot,
|
||||
CommitteeIndex: data.CommitteeIndex,
|
||||
BeaconBlockRoot: data.BeaconBlockRoot,
|
||||
Source: &pb.Checkpoint{
|
||||
Epoch: data.Source.Epoch,
|
||||
Root: data.Source.Root,
|
||||
},
|
||||
Target: &pb.Checkpoint{
|
||||
Epoch: data.Target.Epoch,
|
||||
Root: data.Target.Root,
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, err := client.SignBeaconAttestation(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch resp.State {
|
||||
case pb.ResponseState_DENIED:
|
||||
return nil, ErrDenied
|
||||
case pb.ResponseState_FAILED:
|
||||
return nil, ErrCannotSign
|
||||
}
|
||||
return bls.SignatureFromBytes(resp.Signature)
|
||||
}
|
||||
|
||||
// RefreshValidatingKeys refreshes the list of validating keys from the remote signer.
|
||||
func (km *Remote) RefreshValidatingKeys() error {
|
||||
listerClient := pb.NewListerClient(km.conn)
|
||||
listAccountsReq := &pb.ListAccountsRequest{
|
||||
Paths: km.paths,
|
||||
}
|
||||
resp, err := listerClient.ListAccounts(context.TODO(), listAccountsReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.State == pb.ResponseState_DENIED {
|
||||
return errors.New("attempt to fetch keys denied")
|
||||
}
|
||||
if resp.State == pb.ResponseState_FAILED {
|
||||
return errors.New("attempt to fetch keys failed")
|
||||
}
|
||||
|
||||
verificationRegexes := pathsToVerificationRegexes(km.paths)
|
||||
accounts := make(map[[48]byte]*accountInfo, len(resp.Accounts))
|
||||
for _, account := range resp.Accounts {
|
||||
verified := false
|
||||
for _, verificationRegex := range verificationRegexes {
|
||||
if verificationRegex.Match([]byte(account.Name)) {
|
||||
verified = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !verified {
|
||||
log.WithField("path", account.Name).Warn("Received unwanted account from server; ignoring")
|
||||
continue
|
||||
}
|
||||
account := &accountInfo{
|
||||
Name: account.Name,
|
||||
PubKey: account.PublicKey,
|
||||
}
|
||||
accounts[bytesutil.ToBytes48(account.PubKey)] = account
|
||||
}
|
||||
km.accounts = accounts
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathsToVerificationRegexes turns path specifiers in to regexes to ensure accounts we are given are good.
|
||||
func pathsToVerificationRegexes(paths []string) []*regexp.Regexp {
|
||||
regexes := make([]*regexp.Regexp, 0, len(paths))
|
||||
for _, path := range paths {
|
||||
log := log.WithField("path", path)
|
||||
parts := strings.Split(path, "/")
|
||||
if len(parts) == 0 || parts[0] == "" {
|
||||
log.Debug("Invalid path")
|
||||
continue
|
||||
}
|
||||
if len(parts) == 1 {
|
||||
parts = append(parts, ".*")
|
||||
}
|
||||
parts[1] = strings.TrimPrefix(parts[1], "^")
|
||||
var specifier string
|
||||
if strings.HasSuffix(parts[1], "$") {
|
||||
specifier = fmt.Sprintf("^%s/%s", parts[0], parts[1])
|
||||
} else {
|
||||
specifier = fmt.Sprintf("^%s/%s$", parts[0], parts[1])
|
||||
}
|
||||
regex, err := regexp.Compile(specifier)
|
||||
if err != nil {
|
||||
log.WithField("specifier", specifier).WithError(err).Warn("Invalid path regex")
|
||||
continue
|
||||
}
|
||||
regexes = append(regexes, regex)
|
||||
}
|
||||
return regexes
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestPathsToVerificationRegexes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
paths []string
|
||||
regexes []string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "Empty",
|
||||
regexes: []string{},
|
||||
},
|
||||
{
|
||||
name: "IgnoreBadPaths",
|
||||
paths: []string{"", "/", "/Account"},
|
||||
regexes: []string{},
|
||||
},
|
||||
{
|
||||
name: "Simple",
|
||||
paths: []string{"Wallet/Account"},
|
||||
regexes: []string{"^Wallet/Account$"},
|
||||
},
|
||||
{
|
||||
name: "Multiple",
|
||||
paths: []string{"Wallet/Account1", "Wallet/Account2"},
|
||||
regexes: []string{"^Wallet/Account1$", "^Wallet/Account2$"},
|
||||
},
|
||||
{
|
||||
name: "IgnoreInvalidRegex",
|
||||
paths: []string{"Wallet/Account1", "Bad/***", "Wallet/Account2"},
|
||||
regexes: []string{"^Wallet/Account1$", "^Wallet/Account2$"},
|
||||
},
|
||||
{
|
||||
name: "TidyExistingAnchors",
|
||||
paths: []string{"Wallet/^.*$", "Wallet/Foo.*Bar$", "Wallet/^Account"},
|
||||
regexes: []string{"^Wallet/.*$", "^Wallet/Foo.*Bar$", "^Wallet/Account$"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
regexes := pathsToVerificationRegexes(test.paths)
|
||||
require.Equal(t, len(test.regexes), len(regexes), "Unexpected number of regexes")
|
||||
for i := range regexes {
|
||||
require.Equal(t, test.regexes[i], regexes[i].String(), "Unexpected regex %d", i)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
)
|
||||
|
||||
var validClientCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIEITCCAgmgAwIBAgIQXUJWQZgVO4IX+zlWGI1/mTANBgkqhkiG9w0BAQsFADAU
|
||||
MRIwEAYDVQQDEwlBdHRlc3RhbnQwHhcNMjAwMzE3MDgwNjU3WhcNMjEwOTE3MDc1
|
||||
OTUyWjASMRAwDgYDVQQDEwdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZOgfcP
|
||||
jVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+yPAT
|
||||
4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9tOAj
|
||||
G7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq825l
|
||||
cEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4VOD8a
|
||||
eC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
|
||||
A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQDGCE0
|
||||
3k4rHzB+Ycf3pt1MzeDPgzAfBgNVHSMEGDAWgBScIYZa4dQBIW/gVwR0ctGCuHhe
|
||||
9jANBgkqhkiG9w0BAQsFAAOCAgEAHG/EfvqIwbhYfci+zRCYC7aQPuvhivJblBwN
|
||||
mbXo2qsxvje1hcKm0ptJLOy/cjJzeLJYREhQlXDPRJC/xgELnbXRjgag82r35+pf
|
||||
wVJwP6Yw53VCM3o0QKsUrKyMm4sAijOBrJyqpB5untAieZsry5Bfj0S4YobbtdJa
|
||||
VsEioU07fVVczf5lYN0XrLgRnXq3LMkTiZ6drFiqLkwmXQZVxNujmcaFSm7yCALl
|
||||
EdhYNmaqedS5me5UOGxwPacrsZwWF9dvMsl3OswgTcaGdsUtx2/q+S2vbZUAM/Gw
|
||||
qaTanDfvVtVTF7KzVN9hiqKe4mO0HHHK2HWJYBLdRJjInOgRW+53hCmUhLxD+Dq+
|
||||
31jLKxn/Y4hyH9E+55b1sJHCFpsbEtVD53fojiH2C/uLbhq4Wr1PXgOoxzf2KeSQ
|
||||
B3ENu8C4b6AlNhqOnz5zeDcx8Ug0vMfVDAwf6RAYMG5b/MoWNKcLNXhk8H1nbVkt
|
||||
16ppjh6I27JqfNqfP2J/p3BF++ZugZuWfN9DRaJ6UPz+yyF7eW8fyDAQNl7LS0Kh
|
||||
8PlF5cYvyIIKVHe38Mn8ZAWboKUs0xNv2vhA9V/4Q1ZzAEkXjmbk8H26sjGvJnvg
|
||||
Lgm/+6LVWR4EnUlU8aEWASEpTWq2lSRF3ZOvNstHnufyiDfcwDcl/IKKQiVQQ3mX
|
||||
tw8Jf74=
|
||||
-----END CERTIFICATE-----`
|
||||
var validClientKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZO
|
||||
gfcPjVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+
|
||||
yPAT4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9
|
||||
tOAjG7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq
|
||||
825lcEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4V
|
||||
OD8aeC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABAoIBAQCjV2MVcDQmHDhw
|
||||
FH95A5bVu3TgM8flfs64rwYU25iPIexuqDs+kOMsh/xMLfrkgGz7BGyIhYGwZLK1
|
||||
3ekjyHHPS8qYuAyFtCelSEDE7tRDOAhLEFDq7gCUloGQ561EsQP3CMa1OZwZpgSh
|
||||
PwM2ruRAFIK0E95NvOfqsv0gYN0Svo7hYjNsvW6ok/ZGMyN2ikcRR04wGOFOGjfT
|
||||
xTmfURc9ejnOjHAOqLTpToPwM1/gWWR2iMQefC4njy4MO2BXqOPUmHxmmR4PYhu2
|
||||
8EcKbyRs+/fvL3GgD3VAlOe5vnkfBzssQhHmexgSk5lHZrcSxUGXYGrYKPAeV2mk
|
||||
5HRBWp0RAoGBAOUn5w+NCAugcTGP0hfNlyGXsXqUZvnMyFWvUcxgzgPlJyEyDnKn
|
||||
aIb1DFOF2HckCfLZdrHqqgaF6K3TDvW9BgSKIsvISpo1S95ZPD6DKUo6YQ10CQRW
|
||||
q/ZZVbxtFksVgFRGYpCVmPNULmx7CiXDT1b/suwNMAwCZwiNPTSvKQVLAoGBAMaj
|
||||
zDo1/eepRslqnz5s8hh7dGEjfG/ZJcLgAJAxCyAgnIP4Tls7QkNhCVp9LcN6i1bc
|
||||
CnT6AIuZRXSJWEdp4k2QnVFUmh9Q5MGgwrKYSY5M/1puTISlF1yQ8J6FX8BlDVmy
|
||||
4dyaSyC0RIvgBzF9/KBDxxmJcHgGQ0awLeeyl4cvAoGBAN83FS3itLmOmXQrofyp
|
||||
uNNyDeFXeU9OmL5OPqGUkljc+Favib9JLtp3DIC3WfoD0uUJy0LXULN18QaRFnts
|
||||
mtYFMIvMGE9KJxL5XWOPI8M4Rp1yL+5X9r3Km2cl45dT5GMzBIPOFOTBVU86MtJC
|
||||
A6C9Bi5FUk4AcRi1a69MB+stAoGAWNiwoyS9IV38dGCFQ4W1LzAg2MXnhZuJoUVR
|
||||
2yykfkU33Gs2mOXDeKGxblDpJDLumfYnkzSzA72VbE92NdLtTqYtR1Bg8zraZqTC
|
||||
EOG+nLBh0o/dF8ND1LpbdXvQXRyVwRYaofI9Qi5/LlUQwplIYmKObiSkMnsSok5w
|
||||
6d5emi8CgYBjtUihOFaAmgqkTHOn4j4eKS1O7/H8QQSVe5M0bocmAIbgJ4At3GnI
|
||||
E1JcIY2SZtSwAWs6aQPGE42gwsNCCsQWdJNtViO23JbCwlcPToC4aDfc0JJNaYqp
|
||||
oVV7C5jmJh9VRd2tXIXIZMMNOfThfNf2qDQuJ1S2t5KugozFiRsHUg==
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
func TestNewRemoteWallet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts string
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "Empty",
|
||||
opts: ``,
|
||||
err: "unexpected end of JSON input",
|
||||
},
|
||||
{
|
||||
name: "NoAccounts",
|
||||
opts: `{}`,
|
||||
err: "at least one account specifier is required",
|
||||
},
|
||||
{
|
||||
name: "NoCertificates",
|
||||
opts: `{"accounts":["foo"]}`,
|
||||
err: "certificates are required",
|
||||
},
|
||||
{
|
||||
name: "NoClientCertificate",
|
||||
opts: `{"accounts":["foo"],"certificates":{}}`,
|
||||
err: "client certificate is required",
|
||||
},
|
||||
{
|
||||
name: "NoClientKey",
|
||||
opts: `{"accounts":["foo"],"certificates":{"client_cert":"foo"}}`,
|
||||
err: "client key is required",
|
||||
},
|
||||
{
|
||||
name: "MissingClientKey",
|
||||
opts: `{"accounts":["foo"],"certificates":{"client_cert":"foo","client_key":"bar"}}`,
|
||||
err: "failed to obtain client's certificate and/or key: open foo: no such file or directory",
|
||||
},
|
||||
{
|
||||
name: "BadClientCert",
|
||||
clientCert: `bad`,
|
||||
clientKey: validClientKey,
|
||||
opts: `{"accounts":["foo"],"certificates":{"client_cert":"<<clientcert>>","client_key":"<<clientkey>>"}}`,
|
||||
err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in certificate input",
|
||||
},
|
||||
{
|
||||
name: "BadClientKey",
|
||||
clientCert: validClientCert,
|
||||
clientKey: `bad`,
|
||||
opts: `{"accounts":["foo"],"certificates":{"client_cert":"<<clientcert>>","client_key":"<<clientkey>>"}}`,
|
||||
err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in key input",
|
||||
},
|
||||
{
|
||||
name: "MissingCACert",
|
||||
clientCert: validClientCert,
|
||||
clientKey: validClientKey,
|
||||
opts: `{"accounts":["foo"],"certificates":{"client_cert":"<<clientcert>>","client_key":"<<clientkey>>","ca_cert":"bad"}}`,
|
||||
err: "failed to obtain server's CA certificate: open bad: no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
if test.caCert != "" || test.clientCert != "" || test.clientKey != "" {
|
||||
dir := fmt.Sprintf("%s/%s", testutil.TempDir(), test.name)
|
||||
require.NoError(t, os.MkdirAll(dir, 0777))
|
||||
if test.caCert != "" {
|
||||
caCertPath := fmt.Sprintf("%s/ca.crt", dir)
|
||||
err := ioutil.WriteFile(caCertPath, []byte(test.caCert), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write CA certificate")
|
||||
test.opts = strings.ReplaceAll(test.opts, "<<cacert>>", caCertPath)
|
||||
}
|
||||
if test.clientCert != "" {
|
||||
clientCertPath := fmt.Sprintf("%s/client.crt", dir)
|
||||
err := ioutil.WriteFile(clientCertPath, []byte(test.clientCert), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write client certificate")
|
||||
test.opts = strings.ReplaceAll(test.opts, "<<clientcert>>", clientCertPath)
|
||||
}
|
||||
if test.clientKey != "" {
|
||||
clientKeyPath := fmt.Sprintf("%s/client.key", dir)
|
||||
err := ioutil.WriteFile(clientKeyPath, []byte(test.clientKey), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write client key")
|
||||
test.opts = strings.ReplaceAll(test.opts, "<<clientkey>>", clientKeyPath)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err := keymanager.NewRemoteWallet(test.opts)
|
||||
if test.err == "" {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.ErrorContains(t, test.err, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
e2wallet "github.com/wealdtech/go-eth2-wallet"
|
||||
filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem"
|
||||
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
|
||||
)
|
||||
|
||||
type walletOpts struct {
|
||||
Location string `json:"location"`
|
||||
Accounts []string `json:"accounts"`
|
||||
Passphrases []string `json:"passphrases"`
|
||||
}
|
||||
|
||||
var walletOptsHelp = `The wallet key manager stores keys in a local encrypted store. The options are:
|
||||
- location This is the location to look for wallets. If not supplied it will
|
||||
use the standard (operating system-dependent) path.
|
||||
- accounts This is a list of account specifiers. An account specifier is of
|
||||
the form <wallet name>/[account name], where the account name can be a
|
||||
regular expression. If the account specifier is just <wallet name> all
|
||||
accounts in that wallet will be used. Multiple account specifiers can be
|
||||
supplied if required.
|
||||
- passphrase This is the passphrase used to encrypt the accounts when they
|
||||
were created. Multiple passphrases can be supplied if required.
|
||||
|
||||
An sample keymanager options file (with annotations; these should be removed if
|
||||
using this as a template) is:
|
||||
|
||||
{
|
||||
"location": "/wallets", // Look for wallets in the directory '/wallets'
|
||||
"accounts": ["Validators/Account.*"], // Use all accounts in the 'Validators' wallet starting with 'Account'
|
||||
"passphrases": ["secret1","secret2"] // Use the passphrases 'secret1' and 'secret2' to decrypt accounts
|
||||
}`
|
||||
|
||||
// NewWallet creates a key manager populated with the keys from a wallet at the given path.
|
||||
func NewWallet(input string) (KeyManager, string, error) {
|
||||
opts := &walletOpts{}
|
||||
err := json.Unmarshal([]byte(input), opts)
|
||||
if err != nil {
|
||||
return nil, walletOptsHelp, err
|
||||
}
|
||||
|
||||
if len(opts.Accounts) == 0 {
|
||||
return nil, walletOptsHelp, errors.New("at least one account specifier is required")
|
||||
}
|
||||
|
||||
if len(opts.Passphrases) == 0 {
|
||||
return nil, walletOptsHelp, errors.New("at least one passphrase is required to decrypt accounts")
|
||||
}
|
||||
for i, passphrase := range opts.Passphrases {
|
||||
if strings.HasPrefix(passphrase, "$") {
|
||||
envPassphrase := os.Getenv(strings.TrimPrefix(passphrase, "$"))
|
||||
if envPassphrase != "" {
|
||||
// N.B. We do not log here if the environment variable is not found, as it is possible that this is actually a
|
||||
// passphrase that just happens to begin with the '$' character. If this is a missing environment variable it will
|
||||
// be noticed when the account fails to decrypt.
|
||||
opts.Passphrases[i] = envPassphrase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
km := &Wallet{
|
||||
accounts: make(map[[48]byte]e2wtypes.Account),
|
||||
}
|
||||
|
||||
if strings.Contains(opts.Location, "$") || strings.Contains(opts.Location, "~") || strings.Contains(opts.Location, "%") {
|
||||
log.WithField("path", opts.Location).Warn("Keystore path contains unexpanded shell expansion characters")
|
||||
}
|
||||
var store e2wtypes.Store
|
||||
if opts.Location == "" {
|
||||
store = filesystem.New()
|
||||
} else {
|
||||
store = filesystem.New(filesystem.WithLocation(opts.Location))
|
||||
}
|
||||
ctx := context.Background()
|
||||
for _, path := range opts.Accounts {
|
||||
parts := strings.Split(path, "/")
|
||||
if parts[0] == "" {
|
||||
return nil, walletOptsHelp, fmt.Errorf("did not understand account specifier %q", path)
|
||||
}
|
||||
wallet, err := e2wallet.OpenWallet(parts[0], e2wallet.WithStore(store))
|
||||
if err != nil {
|
||||
return nil, walletOptsHelp, err
|
||||
}
|
||||
accountSpecifier := "^.*$"
|
||||
if len(parts) > 1 && len(parts[1]) > 0 {
|
||||
accountSpecifier = fmt.Sprintf("^%s$", parts[1])
|
||||
}
|
||||
re := regexp.MustCompile(accountSpecifier)
|
||||
for account := range wallet.Accounts(ctx) {
|
||||
log := log.WithField("account", fmt.Sprintf("%s/%s", wallet.Name(), account.Name()))
|
||||
if re.Match([]byte(account.Name())) {
|
||||
pubKey := bytesutil.ToBytes48(account.PublicKey().Marshal())
|
||||
unlocked := false
|
||||
for _, passphrase := range opts.Passphrases {
|
||||
locker, ok := account.(e2wtypes.AccountLocker)
|
||||
if !ok {
|
||||
log.WithError(err).Trace("Account does not implement the AccountLocker interface")
|
||||
continue
|
||||
}
|
||||
if err := locker.Unlock(ctx, []byte(passphrase)); err != nil {
|
||||
log.WithError(err).Trace("Failed to unlock account with one of the supplied passphrases")
|
||||
} else {
|
||||
km.accounts[pubKey] = account
|
||||
unlocked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !unlocked {
|
||||
log.Warn("Failed to unlock account with any supplied passphrase; cannot validate with this key")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return km, walletOptsHelp, nil
|
||||
}
|
||||
|
||||
// Wallet is a key manager that loads keys from a local Ethereum 2 wallet.
|
||||
type Wallet struct {
|
||||
accounts map[[48]byte]e2wtypes.Account
|
||||
}
|
||||
|
||||
// FetchValidatingKeys fetches the list of public keys that should be used to validate with.
|
||||
func (km *Wallet) FetchValidatingKeys() ([][48]byte, error) {
|
||||
res := make([][48]byte, 0, len(km.accounts))
|
||||
for pubKey := range km.accounts {
|
||||
res = append(res, pubKey)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Sign signs a message for the validator to broadcast.
|
||||
func (km *Wallet) Sign(ctx context.Context, pubKey [48]byte, root [32]byte) (bls.Signature, error) {
|
||||
account, exists := km.accounts[pubKey]
|
||||
if !exists {
|
||||
return nil, ErrNoSuchKey
|
||||
}
|
||||
// TODO(#4817) Update with new library to remove domain here.
|
||||
signer, ok := account.(e2wtypes.AccountSigner)
|
||||
if !ok {
|
||||
return nil, errors.New("account does not implement the AccountSigner interface")
|
||||
}
|
||||
sig, err := signer.Sign(ctx, root[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bls.SignatureFromBytes(sig.Marshal())
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
|
||||
filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem"
|
||||
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
|
||||
)
|
||||
|
||||
func SetupWallet(t *testing.T) string {
|
||||
path, err := ioutil.TempDir("", "")
|
||||
require.NoError(t, err)
|
||||
store := filesystem.New(filesystem.WithLocation(path))
|
||||
encryptor := keystorev4.New()
|
||||
|
||||
// Create wallets with keys.
|
||||
ctx := context.Background()
|
||||
w1, err := nd.CreateWallet(ctx, "Wallet 1", store, encryptor)
|
||||
unlocker, ok := w1.(e2wtypes.WalletLocker)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, unlocker.Unlock(ctx, nil))
|
||||
creator, ok := w1.(e2wtypes.WalletAccountCreator)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err, "Failed to create wallet")
|
||||
require.NoError(t, err, "Failed to unlock wallet")
|
||||
_, err = creator.CreateAccount(ctx, "Account 1", []byte("foo"))
|
||||
require.NoError(t, err, "Failed to create account 1")
|
||||
_, err = creator.CreateAccount(ctx, "Account 2", []byte("bar"))
|
||||
require.NoError(t, err, "Failed to create account 2")
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func wallet(t *testing.T, opts string) keymanager.KeyManager {
|
||||
km, _, err := keymanager.NewWallet(opts)
|
||||
require.NoError(t, err)
|
||||
return km
|
||||
}
|
||||
|
||||
func TestMultiplePassphrases(t *testing.T) {
|
||||
path := SetupWallet(t)
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(path))
|
||||
}()
|
||||
tests := []struct {
|
||||
name string
|
||||
wallet keymanager.KeyManager
|
||||
accounts int
|
||||
}{
|
||||
{
|
||||
name: "Neither",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["neither"]}`, path)),
|
||||
accounts: 0,
|
||||
},
|
||||
{
|
||||
name: "Foo",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["foo"]}`, path)),
|
||||
accounts: 1,
|
||||
},
|
||||
{
|
||||
name: "Bar",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["bar"]}`, path)),
|
||||
accounts: 1,
|
||||
},
|
||||
{
|
||||
name: "Both",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["foo","bar"]}`, path)),
|
||||
accounts: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
keys, err := test.wallet.FetchValidatingKeys()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.accounts, len(keys), "Found %d keys", len(keys))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvPassphrases(t *testing.T) {
|
||||
path := SetupWallet(t)
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(path))
|
||||
}()
|
||||
|
||||
err := os.Setenv("TESTENVPASSPHRASES_NEITHER", "neither")
|
||||
require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_NEITHER")
|
||||
defer func() {
|
||||
err := os.Unsetenv("TESTENVPASSPHRASES_NEITHER")
|
||||
require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_NEITHER")
|
||||
}()
|
||||
err = os.Setenv("TESTENVPASSPHRASES_FOO", "foo")
|
||||
require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_FOO")
|
||||
defer func() {
|
||||
err := os.Unsetenv("TESTENVPASSPHRASES_FOO")
|
||||
require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_FOO")
|
||||
}()
|
||||
err = os.Setenv("TESTENVPASSPHRASES_BAR", "bar")
|
||||
require.NoError(t, err, "Error setting environment variable TESTENVPASSPHRASES_BAR")
|
||||
defer func() {
|
||||
err := os.Unsetenv("TESTENVPASSPHRASES_BAR")
|
||||
require.NoError(t, err, "Error unsetting environment variable TESTENVPASSPHRASES_BAR")
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
wallet keymanager.KeyManager
|
||||
accounts int
|
||||
}{
|
||||
{
|
||||
name: "Neither",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_NEITHER"]}`, path)),
|
||||
accounts: 0,
|
||||
},
|
||||
{
|
||||
name: "Foo",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_FOO"]}`, path)),
|
||||
accounts: 1,
|
||||
},
|
||||
{
|
||||
name: "Bar",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_BAR"]}`, path)),
|
||||
accounts: 1,
|
||||
},
|
||||
{
|
||||
name: "Both",
|
||||
wallet: wallet(t, fmt.Sprintf(`{"location":%q,"accounts":["Wallet 1"],"passphrases":["$TESTENVPASSPHRASES_FOO","$TESTENVPASSPHRASES_BAR"]}`, path)),
|
||||
accounts: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
keys, err := test.wallet.FetchValidatingKeys()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.accounts, len(keys), "Found %d keys", len(keys))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,33 +4,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
runtimeDebug "runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
joonix "github.com/joonix/log"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/cmd"
|
||||
"github.com/prysmaticlabs/prysm/shared/debug"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/journald"
|
||||
"github.com/prysmaticlabs/prysm/shared/logutil"
|
||||
_ "github.com/prysmaticlabs/prysm/shared/maxprocs"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/validator/node"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
prefixed "github.com/x-cray/logrus-prefixed-formatter"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// connTimeout defines a period after which connection to beacon node is cancelled.
|
||||
@@ -52,13 +45,7 @@ var appFlags = []cli.Flag{
|
||||
flags.BeaconRPCGatewayProviderFlag,
|
||||
flags.CertFlag,
|
||||
flags.GraffitiFlag,
|
||||
flags.KeystorePathFlag,
|
||||
flags.SourceDirectories,
|
||||
flags.SourceDirectory,
|
||||
flags.TargetDirectory,
|
||||
flags.PasswordFlag,
|
||||
flags.DisablePenaltyRewardLogFlag,
|
||||
flags.UnencryptedKeysFlag,
|
||||
flags.InteropStartIndex,
|
||||
flags.InteropNumValidators,
|
||||
flags.EnableRPCFlag,
|
||||
@@ -70,15 +57,12 @@ var appFlags = []cli.Flag{
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.GrpcHeadersFlag,
|
||||
flags.GPRCGatewayCorsDomain,
|
||||
flags.KeyManager,
|
||||
flags.KeyManagerOpts,
|
||||
flags.DisableAccountMetricsFlag,
|
||||
cmd.MonitoringHostFlag,
|
||||
flags.MonitoringPortFlag,
|
||||
cmd.DisableMonitoringFlag,
|
||||
flags.SlasherRPCProviderFlag,
|
||||
flags.SlasherCertFlag,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.WalletDirFlag,
|
||||
flags.EnableWebFlag,
|
||||
@@ -121,197 +105,6 @@ func main() {
|
||||
app.Commands = []*cli.Command{
|
||||
v2.WalletCommands,
|
||||
v2.AccountCommands,
|
||||
{
|
||||
Name: "accounts",
|
||||
Category: "accounts",
|
||||
Usage: "defines useful functions for interacting with the validator client's account",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "create",
|
||||
Description: `creates a new validator account keystore containing private keys for Ethereum 2.0 -
|
||||
this command outputs a deposit data string which can be used to deposit Ether into the ETH1.0 deposit
|
||||
contract in order to activate the validator client`,
|
||||
Flags: cmd.WrapFlags(append(featureconfig.ActiveFlags(featureconfig.ValidatorFlags),
|
||||
[]cli.Flag{
|
||||
flags.KeystorePathFlag,
|
||||
flags.PasswordFlag,
|
||||
cmd.ChainConfigFileFlag,
|
||||
}...)),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
featureconfig.ConfigureValidator(cliCtx)
|
||||
|
||||
if cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
||||
chainConfigFileName := cliCtx.String(cmd.ChainConfigFileFlag.Name)
|
||||
params.LoadChainConfigFile(chainConfigFileName)
|
||||
}
|
||||
|
||||
keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, true /*confirmPassword*/)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not list keys")
|
||||
return nil
|
||||
}
|
||||
if _, _, err := v1.CreateValidatorAccount(keystorePath, passphrase); err != nil {
|
||||
log.WithField("err", err.Error()).Fatalf("Could not create validator at path: %s", keystorePath)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "keys",
|
||||
Description: `lists the private keys for 'keystore' keymanager keys`,
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.KeystorePathFlag,
|
||||
flags.PasswordFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not list keys")
|
||||
}
|
||||
if err := v1.PrintPublicAndPrivateKeys(keystorePath, passphrase); err != nil {
|
||||
log.WithError(err).Errorf("Could not list private and public keys in path %s", keystorePath)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "status",
|
||||
Description: `list the validator status for existing validator keys`,
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
cmd.GrpcMaxCallRecvMsgSizeFlag,
|
||||
flags.BeaconRPCProviderFlag,
|
||||
flags.CertFlag,
|
||||
flags.GrpcHeadersFlag,
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.KeyManager,
|
||||
flags.KeyManagerOpts,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
var err error
|
||||
var pubKeys [][]byte
|
||||
if cliCtx.String(flags.KeyManager.Name) == "" {
|
||||
keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pubKeys, err = v1.ExtractPublicKeysFromKeyStore(keystorePath, passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(cliCtx.Context, connTimeout)
|
||||
defer cancel()
|
||||
dialOpts := client.ConstructDialOptions(
|
||||
cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name),
|
||||
cliCtx.String(flags.CertFlag.Name),
|
||||
strings.Split(cliCtx.String(flags.GrpcHeadersFlag.Name), ","),
|
||||
cliCtx.Uint(flags.GrpcRetriesFlag.Name),
|
||||
cliCtx.Duration(flags.GrpcRetryDelayFlag.Name),
|
||||
grpc.WithBlock())
|
||||
endpoint := cliCtx.String(flags.BeaconRPCProviderFlag.Name)
|
||||
conn, err := grpc.DialContext(ctx, endpoint, dialOpts...)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("Failed to dial beacon node endpoint at %s", endpoint)
|
||||
return err
|
||||
}
|
||||
err = v1.RunStatusCommand(ctx, pubKeys, ethpb.NewBeaconNodeValidatorClient(conn))
|
||||
if closed := conn.Close(); closed != nil {
|
||||
log.WithError(closed).Error("Could not close connection to beacon node")
|
||||
}
|
||||
return err
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "change-password",
|
||||
Description: "changes password for all keys located in a keystore",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.KeystorePathFlag,
|
||||
flags.PasswordFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
keystorePath, oldPassword, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not read keystore path and/or the old password")
|
||||
}
|
||||
|
||||
log.Info("Please enter the new password")
|
||||
newPassword, err := cmd.EnterPassword(true, cmd.StdInPasswordReader{})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not read the new password")
|
||||
}
|
||||
|
||||
err = v1.ChangePassword(keystorePath, oldPassword, newPassword)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Changing password failed")
|
||||
} else {
|
||||
log.Info("Password changed successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "merge",
|
||||
Description: "merges data from several validator databases into a new validator database",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.SourceDirectories,
|
||||
flags.TargetDirectory,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
passedSources := cliCtx.String(flags.SourceDirectories.Name)
|
||||
sources := strings.Split(passedSources, ",")
|
||||
target := cliCtx.String(flags.TargetDirectory.Name)
|
||||
|
||||
if err := v1.Merge(cliCtx.Context, sources, target); err != nil {
|
||||
log.WithError(err).Error("Merging validator data failed")
|
||||
} else {
|
||||
log.Info("Merge completed successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "split",
|
||||
Description: "splits one validator database into several databases - one for each public key",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.SourceDirectory,
|
||||
flags.TargetDirectory,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
return cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
source := cliCtx.String(flags.SourceDirectory.Name)
|
||||
target := cliCtx.String(flags.TargetDirectory.Name)
|
||||
|
||||
if err := v1.Split(cliCtx.Context, source, target); err != nil {
|
||||
log.WithError(err).Error("Splitting validator data failed")
|
||||
} else {
|
||||
log.Info("Split completed successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = appFlags
|
||||
@@ -322,8 +115,6 @@ contract in order to activate the validator client`,
|
||||
return err
|
||||
}
|
||||
|
||||
flags.ComplainOnDeprecatedFlags(ctx)
|
||||
|
||||
format := ctx.String(cmd.LogFormat.Name)
|
||||
switch format {
|
||||
case "text":
|
||||
|
||||
@@ -10,7 +10,10 @@ go_test(
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"//validator/accounts/v1:go_default_library",
|
||||
"//validator/accounts/v2:go_default_library",
|
||||
"//validator/accounts/v2/wallet:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"//validator/keymanager/v2:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
@@ -37,7 +40,6 @@ go_library(
|
||||
"//validator/client:go_default_library",
|
||||
"//validator/db/kv:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"//validator/keymanager/v1:go_default_library",
|
||||
"//validator/keymanager/v2:go_default_library",
|
||||
"//validator/keymanager/v2/direct:go_default_library",
|
||||
"//validator/rpc:go_default_library",
|
||||
|
||||
@@ -5,7 +5,6 @@ package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
@@ -29,7 +28,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
|
||||
"github.com/prysmaticlabs/prysm/validator/rpc"
|
||||
@@ -157,48 +155,39 @@ func (s *ValidatorClient) Close() {
|
||||
}
|
||||
|
||||
func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
|
||||
var keyManagerV1 v1.KeyManager
|
||||
var keyManagerV2 v2.IKeymanager
|
||||
var err error
|
||||
var accountsDir string
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
if cliCtx.IsSet(flags.InteropNumValidators.Name) {
|
||||
numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name)
|
||||
offset := cliCtx.Uint64(flags.InteropStartIndex.Name)
|
||||
keyManagerV2, err = direct.NewInteropKeymanager(cliCtx.Context, offset, numValidatorKeys)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not generate interop keys")
|
||||
}
|
||||
accountsDir = cliCtx.String(flags.KeystorePathFlag.Name)
|
||||
} else {
|
||||
// Read the wallet from the specified path.
|
||||
w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
return nil, errors.New("no wallet found, create a new one with validator wallet-v2 create")
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not open wallet")
|
||||
}
|
||||
s.wallet = w
|
||||
log.WithFields(logrus.Fields{
|
||||
"wallet": w.AccountsDir(),
|
||||
"keymanager-kind": w.KeymanagerKind().String(),
|
||||
}).Info("Opened validator wallet")
|
||||
keyManagerV2, err = w.InitializeKeymanager(
|
||||
cliCtx.Context, false, /* skipMnemonicConfirm */
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not read keymanager for wallet")
|
||||
}
|
||||
if err := w.LockWalletConfigFile(cliCtx.Context); err != nil {
|
||||
log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err)
|
||||
}
|
||||
accountsDir = s.wallet.AccountsDir()
|
||||
if cliCtx.IsSet(flags.InteropNumValidators.Name) {
|
||||
numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name)
|
||||
offset := cliCtx.Uint64(flags.InteropStartIndex.Name)
|
||||
keyManagerV2, err = direct.NewInteropKeymanager(cliCtx.Context, offset, numValidatorKeys)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not generate interop keys")
|
||||
}
|
||||
} else {
|
||||
keyManagerV1, err = selectV1Keymanager(cliCtx)
|
||||
// Read the wallet from the specified path.
|
||||
w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
return nil, errors.New("no wallet found, create a new one with validator wallet-v2 create")
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "could not open wallet")
|
||||
}
|
||||
s.wallet = w
|
||||
log.WithFields(logrus.Fields{
|
||||
"wallet": w.AccountsDir(),
|
||||
"keymanager-kind": w.KeymanagerKind().String(),
|
||||
}).Info("Opened validator wallet")
|
||||
keyManagerV2, err = w.InitializeKeymanager(
|
||||
cliCtx.Context, false, /* skipMnemonicConfirm */
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not read keymanager for wallet")
|
||||
}
|
||||
if err := w.LockWalletConfigFile(cliCtx.Context); err != nil {
|
||||
log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err)
|
||||
}
|
||||
accountsDir = s.wallet.AccountsDir()
|
||||
}
|
||||
|
||||
dataDir := moveDb(cliCtx, accountsDir)
|
||||
@@ -236,7 +225,7 @@ func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := s.registerClientService(keyManagerV1, keyManagerV2); err != nil {
|
||||
if err := s.registerClientService(keyManagerV2); err != nil {
|
||||
return err
|
||||
}
|
||||
if cliCtx.Bool(flags.EnableRPCFlag.Name) {
|
||||
@@ -305,7 +294,7 @@ func (s *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := s.registerClientService(nil, nil); err != nil {
|
||||
if err := s.registerClientService(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.registerRPCService(cliCtx); err != nil {
|
||||
@@ -327,7 +316,6 @@ func (s *ValidatorClient) registerPrometheusService() error {
|
||||
}
|
||||
|
||||
func (s *ValidatorClient) registerClientService(
|
||||
keyManager v1.KeyManager,
|
||||
keyManagerV2 v2.IKeymanager,
|
||||
) error {
|
||||
endpoint := s.cliCtx.String(flags.BeaconRPCProviderFlag.Name)
|
||||
@@ -347,7 +335,6 @@ func (s *ValidatorClient) registerClientService(
|
||||
v, err := client.NewValidatorService(s.cliCtx.Context, &client.Config{
|
||||
Endpoint: endpoint,
|
||||
DataDir: dataDir,
|
||||
KeyManager: keyManager,
|
||||
KeyManagerV2: keyManagerV2,
|
||||
LogValidatorBalances: logValidatorBalances,
|
||||
EmitAccountMetrics: emitAccountMetrics,
|
||||
@@ -440,74 +427,6 @@ func (s *ValidatorClient) registerWebService(cliCtx *cli.Context) error {
|
||||
return s.services.RegisterService(srv)
|
||||
}
|
||||
|
||||
// Selects the key manager depending on the options provided by the user.
|
||||
func selectV1Keymanager(ctx *cli.Context) (v1.KeyManager, error) {
|
||||
manager := strings.ToLower(ctx.String(flags.KeyManager.Name))
|
||||
opts := ctx.String(flags.KeyManagerOpts.Name)
|
||||
if opts == "" {
|
||||
opts = "{}"
|
||||
} else if !strings.HasPrefix(opts, "{") {
|
||||
fileopts, err := ioutil.ReadFile(opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to read keymanager options file")
|
||||
}
|
||||
opts = string(fileopts)
|
||||
}
|
||||
|
||||
if manager == "" {
|
||||
// Attempt to work out keymanager from deprecated vars.
|
||||
if unencryptedKeys := ctx.String(flags.UnencryptedKeysFlag.Name); unencryptedKeys != "" {
|
||||
manager = "unencrypted"
|
||||
opts = fmt.Sprintf(`{"path":%q}`, unencryptedKeys)
|
||||
log.Warn(fmt.Sprintf("--unencrypted-keys flag is deprecated. Please use --keymanager=unencrypted --keymanageropts='%s'", opts))
|
||||
} else if numValidatorKeys := ctx.Uint64(flags.InteropNumValidators.Name); numValidatorKeys > 0 {
|
||||
manager = "interop"
|
||||
opts = fmt.Sprintf(`{"keys":%d,"offset":%d}`, numValidatorKeys, ctx.Uint64(flags.InteropStartIndex.Name))
|
||||
log.Warn(fmt.Sprintf("--interop-num-validators and --interop-start-index flags are deprecated. Please use --keymanager=interop --keymanageropts='%s'", opts))
|
||||
} else if keystorePath := ctx.String(flags.KeystorePathFlag.Name); keystorePath != "" {
|
||||
manager = "keystore"
|
||||
opts = fmt.Sprintf(`{"path":%q,"passphrase":%q}`, keystorePath, ctx.String(flags.PasswordFlag.Name))
|
||||
log.Warn(fmt.Sprintf("--keystore-path flag is deprecated. Please use --keymanager=keystore --keymanageropts='%s'", opts))
|
||||
} else {
|
||||
// Default if no choice made
|
||||
manager = "keystore"
|
||||
passphrase := ctx.String(flags.PasswordFlag.Name)
|
||||
if passphrase == "" {
|
||||
log.Warn("Implicit selection of keymanager is deprecated. Please use --keymanager=keystore or select a different keymanager")
|
||||
} else {
|
||||
opts = fmt.Sprintf(`{"passphrase":%q}`, passphrase)
|
||||
log.Warn(`Implicit selection of keymanager is deprecated. Please use --keymanager=keystore --keymanageropts='{"passphrase":"<password>"}' or select a different keymanager`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var km v1.KeyManager
|
||||
var help string
|
||||
var err error
|
||||
switch manager {
|
||||
case "interop":
|
||||
km, help, err = v1.NewInterop(opts)
|
||||
case "unencrypted":
|
||||
km, help, err = v1.NewUnencrypted(opts)
|
||||
case "keystore":
|
||||
km, help, err = v1.NewKeystore(opts)
|
||||
case "wallet":
|
||||
km, help, err = v1.NewWallet(opts)
|
||||
case "remote":
|
||||
km, help, err = v1.NewRemoteWallet(opts)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown keymanager %q", manager)
|
||||
}
|
||||
if err != nil {
|
||||
if help != "" {
|
||||
// Print help for the keymanager
|
||||
fmt.Println(help)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return km, nil
|
||||
}
|
||||
|
||||
func clearDB(dataDir string, force bool) error {
|
||||
var err error
|
||||
clearDBConfirmed := force
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/rand"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -12,7 +13,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/accounts/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -22,20 +26,37 @@ func TestNode_Builds(t *testing.T) {
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("datadir", testutil.TempDir()+"/datadir", "the node data directory")
|
||||
dir := testutil.TempDir() + "/keystore1"
|
||||
dir := testutil.TempDir() + "/walletpath"
|
||||
passwordDir := testutil.TempDir() + "/password"
|
||||
require.NoError(t, os.MkdirAll(passwordDir, os.ModePerm))
|
||||
passwordFile := filepath.Join(passwordDir, "password.txt")
|
||||
walletPassword := "$$Passw0rdz2$$"
|
||||
require.NoError(t, ioutil.WriteFile(
|
||||
passwordFile,
|
||||
[]byte(walletPassword),
|
||||
os.ModePerm,
|
||||
))
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
defer func() {
|
||||
assert.NoError(t, os.RemoveAll(passwordDir))
|
||||
assert.NoError(t, os.RemoveAll(testutil.TempDir()+"/datadir"))
|
||||
}()
|
||||
set.String("keystore-path", dir, "path to keystore")
|
||||
set.String("password", "1234", "validator account password")
|
||||
set.String("wallet-dir", dir, "path to wallet")
|
||||
set.String("wallet-password-file", passwordFile, "path to wallet password")
|
||||
set.String("keymanager-kind", "direct", "keymanager kind")
|
||||
set.String("verbosity", "debug", "log verbosity")
|
||||
set.Bool("disable-accounts-v2", true, "disabling accounts v2")
|
||||
require.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, passwordFile))
|
||||
context := cli.NewContext(&app, set, nil)
|
||||
w, err := v2.CreateWalletWithKeymanager(context.Context, &v2.CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: dir,
|
||||
KeymanagerKind: v2keymanager.Direct,
|
||||
WalletPassword: walletPassword,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, w.SaveHashedPassword(context.Context))
|
||||
|
||||
require.NoError(t, v1.NewValidatorAccount(dir, "1234"), "Could not create validator account")
|
||||
valClient, err := NewValidatorClient(context)
|
||||
require.NoError(t, err, "Failed to create ValidatorClient")
|
||||
err = valClient.db.Close()
|
||||
|
||||
@@ -84,12 +84,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.EnableWebFlag,
|
||||
flags.WebHostFlag,
|
||||
flags.WebPortFlag,
|
||||
flags.KeyManager,
|
||||
flags.KeyManagerOpts,
|
||||
flags.KeystorePathFlag,
|
||||
flags.PasswordFlag,
|
||||
flags.DisablePenaltyRewardLogFlag,
|
||||
flags.UnencryptedKeysFlag,
|
||||
flags.GraffitiFlag,
|
||||
flags.EnableRPCFlag,
|
||||
flags.RPCHost,
|
||||
@@ -102,12 +97,8 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.GrpcHeadersFlag,
|
||||
flags.SlasherRPCProviderFlag,
|
||||
flags.SlasherCertFlag,
|
||||
flags.SourceDirectories,
|
||||
flags.SourceDirectory,
|
||||
flags.TargetDirectory,
|
||||
flags.DisableAccountMetricsFlag,
|
||||
flags.WalletDirFlag,
|
||||
flags.DeprecatedPasswordsDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user