diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7177a8c..3969b37 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,16 +30,16 @@ jobs: - name: Set env run: | - echo '::set-env name=GO111MODULE::on' + echo "GO111MODULE=on" >> $GITHUB_ENV # Release tag comes from the github reference. RELEASE_TAG=$(echo ${GITHUB_REF} | sed -e 's!.*/!!') - echo "::set-env name=RELEASE_TAG::${RELEASE_TAG}" + echo "RELEASE_TAG=${RELEASE_TAG}" >> $GITHUB_ENV echo "::set-output name=RELEASE_TAG::${RELEASE_TAG}" # Ensure the release tag has expected format. echo ${RELEASE_TAG} | grep -q '^v' || exit 1 # Release version is same as release tag without leading 'v'. RELEASE_VERSION=$(echo ${GITHUB_REF} | sed -e 's!.*/v!!') - echo "::set-env name=RELEASE_VERSION::${RELEASE_VERSION}" + echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV echo "::set-output name=RELEASE_VERSION::${RELEASE_VERSION}" - name: Build diff --git a/cmd/root.go b/cmd/root.go index 7cb9ddb..3ef89eb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -161,7 +161,9 @@ func init() { if err := viper.BindPFlag("basedir", RootCmd.PersistentFlags().Lookup("basedir")); err != nil { panic(err) } - RootCmd.PersistentFlags().MarkDeprecated("basedir", "use --base-dir") + if err := RootCmd.PersistentFlags().MarkDeprecated("basedir", "use --base-dir"); err != nil { + panic(err) + } RootCmd.PersistentFlags().String("base-dir", "", "Base directory for filesystem wallets") if err := viper.BindPFlag("base-dir", RootCmd.PersistentFlags().Lookup("base-dir")); err != nil { panic(err) @@ -170,7 +172,9 @@ func init() { if err := viper.BindPFlag("storepassphrase", RootCmd.PersistentFlags().Lookup("storepassphrase")); err != nil { panic(err) } - RootCmd.PersistentFlags().MarkDeprecated("storepassphrase", "use --store-passphrase") + if err := RootCmd.PersistentFlags().MarkDeprecated("storepassphrase", "use --store-passphrase"); err != nil { + panic(err) + } RootCmd.PersistentFlags().String("store-passphrase", "", "Passphrase for store (if applicable)") if err := viper.BindPFlag("store-passphrase", RootCmd.PersistentFlags().Lookup("store-passphrase")); err != nil { panic(err) @@ -179,7 +183,9 @@ func init() { if err := viper.BindPFlag("walletpassphrase", RootCmd.PersistentFlags().Lookup("walletpassphrase")); err != nil { panic(err) } - RootCmd.PersistentFlags().MarkDeprecated("walletpassphrase", "use --wallet-passphrase") + if err := RootCmd.PersistentFlags().MarkDeprecated("walletpassphrase", "use --wallet-passphrase"); err != nil { + panic(err) + } RootCmd.PersistentFlags().String("wallet-passphrase", "", "Passphrase for wallet (if applicable)") if err := viper.BindPFlag("wallet-passphrase", RootCmd.PersistentFlags().Lookup("wallet-passphrase")); err != nil { panic(err) diff --git a/cmd/validatorinfo.go b/cmd/validatorinfo.go index 935e777..52fcbd6 100644 --- a/cmd/validatorinfo.go +++ b/cmd/validatorinfo.go @@ -163,6 +163,7 @@ func graphData(network string, validatorPubKey []byte) (uint64, spec.Gwei, error } query := fmt.Sprintf(`{"query": "{deposits(where: {validatorPubKey:\"%#x\"}) { id amount withdrawalCredentials }}"}`, validatorPubKey) url := fmt.Sprintf("https://api.thegraph.com/subgraphs/name/%s", subgraph) + // #nosec G107 graphResp, err := http.Post(url, "application/json", bytes.NewBufferString(query)) if err != nil { return 0, 0, errors.Wrap(err, "failed to check if there is already a deposit for this validator") diff --git a/cmd/wallet/import/output.go b/cmd/wallet/import/output.go index a1afd33..1463ce1 100644 --- a/cmd/wallet/import/output.go +++ b/cmd/wallet/import/output.go @@ -48,10 +48,12 @@ func output(ctx context.Context, data *dataOut) (string, error) { res := "" if data.verify { - res = fmt.Sprintf("Wallet name: %s\nWallet type: %s\nWallet UUID: %s\nWallet accounts: %d", data.export.Wallet.Name, data.export.Wallet.Type, data.export.Wallet.ID, len(data.export.Accounts)) - if data.verbose { - for _, account := range data.export.Accounts { - res = fmt.Sprintf("%s\n %s", res, account.Name) + if !data.quiet { + res = fmt.Sprintf("Wallet name: %s\nWallet type: %s\nWallet UUID: %s\nWallet accounts: %d", data.export.Wallet.Name, data.export.Wallet.Type, data.export.Wallet.ID, len(data.export.Accounts)) + if data.verbose { + for _, account := range data.export.Accounts { + res = fmt.Sprintf("%s\n %s", res, account.Name) + } } } } diff --git a/util/depositinfo.go b/util/depositinfo.go index 2cd71ee..5469ca7 100644 --- a/util/depositinfo.go +++ b/util/depositinfo.go @@ -102,20 +102,6 @@ func DepositInfoFromJSON(input []byte) ([]*DepositInfo, error) { return nil, errors.New("no deposits supplied") } - for i := range depositInfo { - if len(depositInfo[i].PublicKey) == 0 { - return nil, fmt.Errorf("no public key for deposit %d", i) - } - if len(depositInfo[i].DepositDataRoot) == 0 { - return nil, fmt.Errorf("no data root for deposit %d", i) - } - if len(depositInfo[i].Signature) == 0 { - return nil, fmt.Errorf("no signature for deposit %d", i) - } - if len(depositInfo[i].WithdrawalCredentials) == 0 { - return nil, fmt.Errorf("no withdrawal credentials for deposit %d", i) - } - } return depositInfo, nil } @@ -131,26 +117,44 @@ func tryV3DepositInfoFromJSON(data []byte) ([]*DepositInfo, error) { if deposit.Version != 3 { return nil, errors.New("incorrect V3 deposit version") } + if deposit.PublicKey == "" { + return nil, errors.New("public key missing") + } publicKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x")) if err != nil { return nil, errors.New("public key invalid") } + if deposit.WithdrawalCredentials == "" { + return nil, errors.New("withdrawal credentials missing") + } withdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x")) if err != nil { return nil, errors.New("withdrawal credentials invalid") } + if deposit.Signature == "" { + return nil, errors.New("signature missing") + } signature, err := hex.DecodeString(strings.TrimPrefix(deposit.Signature, "0x")) if err != nil { return nil, errors.New("signature invalid") } + if deposit.DepositDataRoot == "" { + return nil, errors.New("deposit data root missing") + } depositDataRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositDataRoot, "0x")) if err != nil { return nil, errors.New("deposit data root invalid") } + if deposit.DepositMessageRoot == "" { + return nil, errors.New("deposit message root missing") + } depositMessageRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositMessageRoot, "0x")) if err != nil { return nil, errors.New("deposit message root invalid") } + if deposit.ForkVersion == "" { + return nil, errors.New("fork version missing") + } forkVersion, err := hex.DecodeString(strings.TrimPrefix(deposit.ForkVersion, "0x")) if err != nil { return nil, errors.New("fork version invalid") @@ -181,26 +185,44 @@ func tryCLIDepositInfoFromJSON(data []byte) ([]*DepositInfo, error) { depositInfos := make([]*DepositInfo, len(depositData)) for i, deposit := range depositData { + if deposit.PublicKey == "" { + return nil, errors.New("public key missing") + } publicKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x")) if err != nil { return nil, errors.New("public key invalid") } + if deposit.WithdrawalCredentials == "" { + return nil, errors.New("withdrawal credentials missing") + } withdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x")) if err != nil { return nil, errors.New("withdrawal credentials invalid") } + if deposit.Signature == "" { + return nil, errors.New("signature missing") + } signature, err := hex.DecodeString(strings.TrimPrefix(deposit.Signature, "0x")) if err != nil { return nil, errors.New("signature invalid") } + if deposit.DepositDataRoot == "" { + return nil, errors.New("deposit data root missing") + } depositDataRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositDataRoot, "0x")) if err != nil { return nil, errors.New("deposit data root invalid") } + if deposit.DepositMessageRoot == "" { + return nil, errors.New("deposit message root missing") + } depositMessageRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositMessageRoot, "0x")) if err != nil { return nil, errors.New("deposit message root invalid") } + if deposit.ForkVersion == "" { + return nil, errors.New("fork version missing") + } forkVersion, err := hex.DecodeString(strings.TrimPrefix(deposit.ForkVersion, "0x")) if err != nil { return nil, errors.New("fork version invalid") diff --git a/util/depositinfo_internal_test.go b/util/depositinfo_internal_test.go index d8f5364..176f896 100644 --- a/util/depositinfo_internal_test.go +++ b/util/depositinfo_internal_test.go @@ -83,31 +83,61 @@ func TestCLIDepositInfo(t *testing.T) { input: []byte("invalid"), err: "invalid character 'i' looking for beginning of value", }, + { + name: "PubKeyMissing", + input: []byte(`[{"withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), + err: "public key missing", + }, { name: "PubKeyInvalid", input: []byte(`[{"pubkey":"invalid","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), err: "public key invalid", }, + { + name: "WithdrawalCredentialsMissing", + input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), + err: "withdrawal credentials missing", + }, { name: "WithdrawalCredentialsInvalid", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"invalid","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), err: "withdrawal credentials invalid", }, + { + name: "SignatureMissing", + input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), + err: "signature missing", + }, { name: "SignatureInvalid", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"invalid","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), err: "signature invalid", }, + { + name: "DepositMessageRootMissing", + input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), + err: "deposit message root missing", + }, { name: "DepositMessageRootInvalid", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"invalid","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), err: "deposit message root invalid", }, + { + name: "DepositDataRootMissing", + input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","fork_version":"01020304"}]`), + err: "deposit data root missing", + }, { name: "DepositDataRootInvalid", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"invalid","fork_version":"01020304"}]`), err: "deposit data root invalid", }, + { + name: "ForkVersionMissing", + input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554"}]`), + err: "fork version missing", + }, { name: "ForkVersionInvalid", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"invalid"}]`), @@ -149,31 +179,61 @@ func TestV3DepositInfo(t *testing.T) { input: []byte("invalid"), err: "invalid character 'i' looking for beginning of value", }, + { + name: "PubKeyMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), + err: "public key missing", + }, { name: "PubKeyInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"invalid","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), err: "public key invalid", }, + { + name: "WithdrawalCredentialsMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), + err: "withdrawal credentials missing", + }, { name: "WithdrawalCredentialsInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"invalid","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), err: "withdrawal credentials invalid", }, + { + name: "SignatureMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), + err: "signature missing", + }, { name: "SignatureInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"invalid","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), err: "signature invalid", }, + { + name: "DepositMessageRootMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), + err: "deposit message root missing", + }, { name: "DepositMessageRootInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"invalid","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"0x01020304","version":3}]`), err: "deposit message root invalid", }, + { + name: "DepositDataRootMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","fork_version":"0x01020304","version":3}]`), + err: "deposit data root missing", + }, { name: "DepositDataRootInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"invalid","fork_version":"0x01020304","version":3}]`), err: "deposit data root invalid", }, + { + name: "ForkVersionMissing", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","version":3}]`), + err: "fork version missing", + }, { name: "ForkVersionInvalid", input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","value":32000000000,"signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"invalid","version":3}]`), diff --git a/util/depositinfo_test.go b/util/depositinfo_test.go index 6b195f2..14603a8 100644 --- a/util/depositinfo_test.go +++ b/util/depositinfo_test.go @@ -41,7 +41,7 @@ func TestDepositInfo(t *testing.T) { { name: "Incorrect", input: []byte("{}"), - err: "no public key for deposit 0", + err: "unknown deposit data format", }, { name: "Empty", @@ -52,6 +52,10 @@ func TestDepositInfo(t *testing.T) { name: "V2", input: []byte(`{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","value":32000000000,"deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","version":2}`), }, + { + name: "V3", + input: []byte(`[{"name":"Deposit for interop/00000","account":"interop/00000","pubkey":"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"0x00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","signature":"0xb7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","amount":32000000000,"deposit_data_root":"0x9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","deposit_message_root":"0x139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","fork_version":"0x01020304","version":3}]`), + }, { name: "Launchpad", input: []byte(`[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`), diff --git a/util/networks.go b/util/networks.go index 6905492..402e4b9 100644 --- a/util/networks.go +++ b/util/networks.go @@ -25,6 +25,7 @@ import ( var networks = map[string]string{ "00000000219ab540356cbb839cbe05303d7705fa": "Mainnet", "07b39f4fde4a38bace212b546dac87c58dfe3fdc": "Medalla", + "8c5fecdc472e27bc447696f431e425d02dd46a8c": "Pyrmont", } // Network returns the name of the network., calculated from the deposit contract information. @@ -33,6 +34,10 @@ func Network(ctx context.Context, eth2Client eth2client.Service) (string, error) var address []byte var err error + if eth2Client == nil { + return "", errors.New("no Ethereum 2 client supplied") + } + if provider, isProvider := eth2Client.(eth2client.DepositContractProvider); isProvider { address, err = provider.DepositContractAddress(ctx) if err != nil { @@ -45,11 +50,14 @@ func Network(ctx context.Context, eth2Client eth2client.Service) (string, error) } address = config["DEPOSIT_CONTRACT_ADDRESS"].([]byte) } - // outputIf(debug, fmt.Sprintf("Deposit contract is %#x", address)) - depositContract := fmt.Sprintf("%x", address) - if network, exists := networks[depositContract]; exists { - return network, nil - } - return "Unknown", nil + return network(address), nil +} + +// network returns a network given an Ethereum 1 contract address. +func network(address []byte) string { + if network, exists := networks[fmt.Sprintf("%x", address)]; exists { + return network + } + return "Unknown" } diff --git a/util/networks_internal_test.go b/util/networks_internal_test.go new file mode 100644 index 0000000..2b9f9cd --- /dev/null +++ b/util/networks_internal_test.go @@ -0,0 +1,55 @@ +// Copyright © 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/wealdtech/ethdo/testutil" +) + +func TestNetworksInternal(t *testing.T) { + tests := []struct { + name string + address []byte + expected string + }{ + { + name: "Empty", + expected: "Unknown", + }, + { + name: "Unknown", + address: testutil.HexToBytes("0000000000000000000000000000000000000000"), + expected: "Unknown", + }, + { + name: "Mainnet", + address: testutil.HexToBytes("00000000219ab540356cbb839cbe05303d7705fa"), + expected: "Mainnet", + }, + { + name: "Pyrmont", + address: testutil.HexToBytes("8c5fecdc472e27bc447696f431e425d02dd46a8c"), + expected: "Pyrmont", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + require.Equal(t, test.expected, network(test.address)) + }) + } +} diff --git a/util/networks_test.go b/util/networks_test.go new file mode 100644 index 0000000..5a1549c --- /dev/null +++ b/util/networks_test.go @@ -0,0 +1,136 @@ +// Copyright © 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util_test + +import ( + "context" + "testing" + + eth2client "github.com/attestantio/go-eth2-client" + "github.com/stretchr/testify/require" + "github.com/wealdtech/ethdo/testutil" + "github.com/wealdtech/ethdo/util" +) + +// A mock Ethereum 2 client service that returns supplied deposit information. +type depositETH2Client struct { + address []byte + chainID uint64 + networkID uint64 +} + +// Name returns the name of the client implementation. +func (c *depositETH2Client) Name() string { + return "deposit mock" +} + +// Address returns the address of the client. +func (c *depositETH2Client) Address() string { + return "mock" +} + +// DepositContractAddress provides the Ethereum 1 address of the deposit contract. +func (c *depositETH2Client) DepositContractAddress(ctx context.Context) ([]byte, error) { + return c.address, nil +} + +// DepositContractChainID provides the Ethereum 1 chain ID of the deposit contract. +func (c *depositETH2Client) DepositContractChainID(ctx context.Context) (uint64, error) { + return c.chainID, nil +} + +// DepositContractNetworkID provides the Ethereum 1 network ID of the deposit contract. +func (c *depositETH2Client) DepositContractNetworkID(ctx context.Context) (uint64, error) { + return c.networkID, nil +} + +// A mock Ethereum 2 client service that returns spec information. +type specETH2Client struct { + address []byte +} + +// Name returns the name of the client implementation. +func (c *specETH2Client) Name() string { + return "spec mock" +} + +// Address returns the address of the client. +func (c *specETH2Client) Address() string { + return "mock" +} + +// Spec provides the spec information of the chain. +func (c *specETH2Client) Spec(ctx context.Context) (map[string]interface{}, error) { + return map[string]interface{}{ + "DEPOSIT_CONTRACT_ADDRESS": c.address, + }, nil +} + +func TestNetworks(t *testing.T) { + tests := []struct { + name string + service eth2client.Service + err string + network string + }{ + { + name: "Nil", + err: "no Ethereum 2 client supplied", + }, + { + name: "MainnetDeposit", + service: &depositETH2Client{ + address: testutil.HexToBytes("0x00000000219ab540356cbb839cbe05303d7705fa"), + chainID: 0, + networkID: 0, + }, + network: "Mainnet", + }, + { + name: "MainnetSpec", + service: &specETH2Client{ + address: testutil.HexToBytes("0x00000000219ab540356cbb839cbe05303d7705fa"), + }, + network: "Mainnet", + }, + { + name: "UnknownDeposit", + service: &depositETH2Client{ + address: testutil.HexToBytes("0x1111111111111111111111111111111111111111"), + chainID: 0, + networkID: 0, + }, + network: "Unknown", + }, + { + name: "UnknownSpec", + service: &specETH2Client{ + address: testutil.HexToBytes("0x1111111111111111111111111111111111111111"), + }, + network: "Unknown", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + network, err := util.Network(context.Background(), test.service) + if test.err != "" { + require.EqualError(t, err, test.err) + } else { + require.NoError(t, err) + require.Equal(t, test.network, network) + } + }) + } +} diff --git a/util/validatorexitdata.go b/util/validatorexitdata.go index 9a3f993..2b57a73 100644 --- a/util/validatorexitdata.go +++ b/util/validatorexitdata.go @@ -51,11 +51,17 @@ func (d *ValidatorExitData) UnmarshalJSON(data []byte) error { return errors.Wrap(err, "failed to unmarshal JSON") } + if validatorExitJSON.Data == nil { + return errors.New("data missing") + } d.Data = validatorExitJSON.Data + if validatorExitJSON.ForkVersion == "" { + return errors.New("fork version missing") + } forkVersion, err := hex.DecodeString(strings.TrimPrefix(validatorExitJSON.ForkVersion, "0x")) if err != nil { - return errors.Wrap(err, "failed to parse fork version") + return errors.Wrap(err, "fork version invalid") } copy(d.ForkVersion[:], forkVersion) diff --git a/util/validatorexitdata_test.go b/util/validatorexitdata_test.go index 1b986ef..98730dd 100644 --- a/util/validatorexitdata_test.go +++ b/util/validatorexitdata_test.go @@ -37,6 +37,26 @@ func TestUnmarshal(t *testing.T) { in: []byte(`invalid`), err: "invalid character 'i' looking for beginning of value", }, + { + name: "DataMissing", + in: []byte(`{"fork_version":"0x00000001"}`), + err: "data missing", + }, + { + name: "DataInvalid", + in: []byte(`{"data":{},"fork_version":"0x00000001"}`), + err: "failed to unmarshal JSON: message missing", + }, + { + name: "ForkVersionMissing", + in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"}}`), + err: "fork version missing", + }, + { + name: "ForkVersionInvalid", + in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"invalid"}`), + err: "fork version invalid: encoding/hex: invalid byte: U+0069 'i'", + }, { name: "Good", in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"0x00000001"}`),