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:
Raul Jordan
2020-10-14 17:20:20 -05:00
committed by GitHub
parent 803d7c9bd2
commit a840fa563d
51 changed files with 487 additions and 3286 deletions

View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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

View File

@@ -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",

View File

@@ -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",
],
)

View File

@@ -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
}

View File

@@ -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])
}

View File

@@ -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 := &ethpb.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())
}
}

View File

@@ -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(),
&ethpb.MultipleValidatorStatusRequest{PublicKeys: pubkeys},
).Return(&ethpb.MultipleValidatorStatusResponse{PublicKeys: pubkeys, Indices: indices}, nil /*err*/)
_, err := FetchAccountStatuses(ctx, mockClient, pubkeys)
require.NoError(t, err, "FetchAccountStatuses failed with error")
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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))

View File

@@ -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",

View File

@@ -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

View File

@@ -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 = &ethpb.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 = &ethpb.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(&ethpb.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 = &ethpb.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(&ethpb.SignedAggregateSubmitRequest{}),
).Return(&ethpb.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
&ethpb.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)

View File

@@ -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
}

View File

@@ -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 := &ethpb.IndexedAttestation{
AttestingIndices: []uint64{1, 2},
Data: &ethpb.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 := &ethpb.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 := &ethpb.IndexedAttestation{
AttestingIndices: []uint64{1, 2},
Data: &ethpb.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 := &ethpb.IndexedAttestation{
AttestingIndices: []uint64{1, 2},

View File

@@ -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 = &ethpb.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 = &ethpb.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 = &ethpb.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(&ethpb.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 = &ethpb.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(&ethpb.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 = &ethpb.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(&ethpb.Attestation{}),
).Return(&ethpb.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 = &ethpb.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(&ethpb.Attestation{}),
).Return(&ethpb.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 = &ethpb.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(&ethpb.Attestation{}),
).Return(&ethpb.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: &ethpb.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(&ethpb.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 = &ethpb.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(&ethpb.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 = &ethpb.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(&ethpb.AttestResponse{}, nil /* error */)
validator.SubmitAttestation(context.Background(), 30, validatorPubKey)
validator.SubmitAttestation(context.Background(), 30, pubKey)
assert.Equal(t, 2, len(generatedAttestation.AggregationBits))
}

View File

@@ -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
}

View File

@@ -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 := &ethpb.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
}

View File

@@ -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 := &ethpb.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 := &ethpb.SignedBeaconBlock{
Block: &ethpb.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")
}

View File

@@ -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(&ethpb.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(&ethpb.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(&ethpb.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(&ethpb.SignedBeaconBlock{}),
).Times(2).Return(&ethpb.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(&ethpb.SignedBeaconBlock{}),
).Times(2).Return(&ethpb.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(&ethpb.SignedBeaconBlock{}),
).Return(&ethpb.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 &ethpb.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(&ethpb.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(&ethpb.SignedVoluntaryExit{})).
Return(&ethpb.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(),
))
}

View File

@@ -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,

View File

@@ -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")

View File

@@ -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
}

View File

@@ -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(),
&ethpb.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(),
&ethpb.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(),
&ethpb.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(),
&ethpb.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(),
&ethpb.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: &ethpb.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: &ethpb.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 := &ethpb.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 = &ethpb.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(&ethpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
m.validatorClient.EXPECT().DomainData(
gomock.Any(), // ctx
gomock.Any(), // epoch
).Return(&ethpb.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 = &ethpb.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: &ethpb.DutiesResponse{
Duties: []*ethpb.DutiesResponse_Duty{

View File

@@ -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",
],
)

View File

@@ -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

View File

@@ -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",
],
)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -1,7 +0,0 @@
package v1
import (
"github.com/sirupsen/logrus"
)
var log = logrus.WithField("prefix", "keymanager")

View File

@@ -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)
}

View File

@@ -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)
}
})
}
}

View File

@@ -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
}

View File

@@ -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)
}
})
}
}

View File

@@ -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)
}
})
}
}

View File

@@ -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())
}

View File

@@ -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))
})
}
}

View File

@@ -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":

View File

@@ -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",

View File

@@ -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

View File

@@ -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()

View File

@@ -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,
},
},