Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upload nodeset force stakewise #15

Merged
merged 38 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7dab9f3
Merge pull request #1 from nodeset-org/dev
jclapis Apr 17, 2024
b0d4b64
Merge pull request #10 from nodeset-org/dev
jclapis Apr 30, 2024
e96abb3
Merge pull request #12 from nodeset-org/dev
jclapis May 2, 2024
12afcc7
done
huy-nodeset May 7, 2024
517dbf2
ok
huy-nodeset May 7, 2024
8a46d02
remove forceupload
huy-nodeset May 7, 2024
847a43c
wip
huy-nodeset May 7, 2024
dc1c026
off
huy-nodeset May 8, 2024
5c27418
wip
huy-nodeset May 8, 2024
ced1a7e
bug
huy-nodeset May 8, 2024
f40b4ea
WIP
huy-nodeset May 9, 2024
1060e00
remove state
huy-nodeset May 13, 2024
044eae1
WIP
huy-nodeset May 14, 2024
46f47af
Merge branch 'dev' of github.com:nodeset-org/hyperdrive-stakewise int…
huy-nodeset May 14, 2024
2780f5d
wip
huy-nodeset May 14, 2024
2878a69
wip
huy-nodeset May 14, 2024
6c6f3f1
wip
huy-nodeset May 14, 2024
7cae4c9
simplify logic
huy-nodeset May 15, 2024
90dc7b3
almost done
huy-nodeset May 15, 2024
742e592
clean up
huy-nodeset May 15, 2024
27c73d0
Merge branch 'dev' of github.com:nodeset-org/hyperdrive-stakewise int…
huy-nodeset May 15, 2024
1cba1d9
bump
huy-nodeset May 15, 2024
3da8384
tidy
huy-nodeset May 15, 2024
091dd0f
joes review
huy-nodeset May 15, 2024
e084762
wip
huy-nodeset May 16, 2024
fb31e52
error logging
huy-nodeset May 16, 2024
e0930d2
revert version for now
huy-nodeset May 16, 2024
ba7a0a6
version bump
huy-nodeset May 16, 2024
d54b32e
fix
huy-nodeset May 16, 2024
bd99697
fix
huy-nodeset May 16, 2024
7c0f933
wip
huy-nodeset May 16, 2024
c404b31
ko
huy-nodeset May 16, 2024
2ab31fc
unused line
huy-nodeset May 16, 2024
2395449
refactor
huy-nodeset May 16, 2024
49276c3
refactor
huy-nodeset May 16, 2024
bcbda44
wip
huy-nodeset May 16, 2024
8f56903
verison
huy-nodeset May 16, 2024
81197f8
fix
huy-nodeset May 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions client/nodeset.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package swclient

import (
"strconv"

"github.com/ethereum/go-ethereum/common"
swapi "github.com/nodeset-org/hyperdrive-stakewise/shared/api"
"github.com/rocket-pool/node-manager-core/api/client"
Expand Down Expand Up @@ -38,9 +36,7 @@ func (r *NodesetRequester) SetValidatorsRoot(root common.Hash) (*types.ApiRespon
}

// Upload the aggregated deposit data file to NodeSet's servers
func (r *NodesetRequester) UploadDepositData(bypassBalanceCheck bool) (*types.ApiResponse[swapi.NodesetUploadDepositDataData], error) {
args := map[string]string{
"bypassBalanceCheck": strconv.FormatBool(bypassBalanceCheck),
}
func (r *NodesetRequester) UploadDepositData() (*types.ApiResponse[swapi.NodesetUploadDepositDataData], error) {
args := map[string]string{}
return client.SendGetRequest[swapi.NodesetUploadDepositDataData](r, "upload-deposit-data", "UploadDepositData", args)
}
19 changes: 19 additions & 0 deletions common/nodeset-client.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,22 @@ func (c *NodesetClient) submitRequest(ctx context.Context, method string, body i
logger.Debug("NodeSet response:", slog.String(log.CodeKey, resp.Status), slog.String(log.BodyKey, string(bytes)))
return bytes, nil
}

func IsUploadedToNodeset(pubKey beacon.ValidatorPubkey, registeredPubkeys []beacon.ValidatorPubkey) bool {
for _, registeredPubKey := range registeredPubkeys {
if registeredPubKey == pubKey {
return true
}
}
return false
}

func IsRegisteredToStakewise(pubKey beacon.ValidatorPubkey, statuses map[beacon.ValidatorPubkey]beacon.ValidatorStatus) bool {
// TODO: Implement
return false
}

func IsUploadedStakewise(pubKey beacon.ValidatorPubkey, statuses map[beacon.ValidatorPubkey]beacon.ValidatorStatus) bool {
// TODO: Implement
return false
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/goccy/go-json v0.10.2
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515155018-d97df5b61692
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515161352-9f17d9f9bfa5
github.com/rocket-pool/batch-query v1.0.0
github.com/rocket-pool/node-manager-core v0.3.1-0.20240515153751-dd88806cef89
github.com/urfave/cli/v2 v2.27.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515155018-d97df5b61692 h1:LAHl/tj+l4UIZjJv+73S1EIb0stK3AGyw5X9odfC9x4=
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515155018-d97df5b61692/go.mod h1:cPMY0KDqaoJXN2dUkC1ChhfjsguHDPLYcSbBskIPb/s=
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515161352-9f17d9f9bfa5 h1:VyLPdNB285Rp6brVrJk7u5VfbdVKMBx6ilXciXCX8VI=
github.com/nodeset-org/hyperdrive-daemon v0.4.2-dev.0.20240515161352-9f17d9f9bfa5/go.mod h1:cPMY0KDqaoJXN2dUkC1ChhfjsguHDPLYcSbBskIPb/s=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
Expand Down
145 changes: 86 additions & 59 deletions server/nodeset/upload-deposit-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ import (
"net/url"

"github.com/goccy/go-json"
eth2types "github.com/wealdtech/go-eth2-types/v2"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/gorilla/mux"
swcommon "github.com/nodeset-org/hyperdrive-stakewise/common"
"github.com/rocket-pool/node-manager-core/eth"

duserver "github.com/nodeset-org/hyperdrive-daemon/module-utils/server"
swapi "github.com/nodeset-org/hyperdrive-stakewise/shared/api"
"github.com/rocket-pool/node-manager-core/api/server"
"github.com/rocket-pool/node-manager-core/api/types"
"github.com/rocket-pool/node-manager-core/beacon"
"github.com/rocket-pool/node-manager-core/eth"
"github.com/rocket-pool/node-manager-core/utils/input"
"github.com/rocket-pool/node-manager-core/wallet"
eth2types "github.com/wealdtech/go-eth2-types/v2"
)

const (
pendingState string = "PENDING"
validatorDepositCost float64 = 0.01
)

// ===============
Expand All @@ -33,9 +38,7 @@ func (f *nodesetUploadDepositDataContextFactory) Create(args url.Values) (*nodes
c := &nodesetUploadDepositDataContext{
handler: f.handler,
}
inputErrs := []error{
server.ValidateArg("bypassBalanceCheck", args, input.ValidateBool, &c.bypassBalanceCheck),
}
inputErrs := []error{}
return c, errors.Join(inputErrs...)
}

Expand All @@ -48,10 +51,8 @@ func (f *nodesetUploadDepositDataContextFactory) RegisterRoute(router *mux.Route
// ===============
// === Context ===
// ===============

type nodesetUploadDepositDataContext struct {
handler *NodesetHandler
bypassBalanceCheck bool
handler *NodesetHandler
}

func (c *nodesetUploadDepositDataContext) PrepareData(data *swapi.NodesetUploadDepositDataData, walletStatus wallet.WalletStatus, opts *bind.TransactOpts) (types.ResponseStatus, error) {
Expand All @@ -61,86 +62,112 @@ func (c *nodesetUploadDepositDataContext) PrepareData(data *swapi.NodesetUploadD
w := sp.GetWallet()
ec := sp.GetEthClient()
ctx := c.handler.ctx

data.EthPerKey = validatorDepositCost
// Requirements
err := sp.RequireStakewiseWalletReady(ctx, walletStatus)
if err != nil {
return types.ResponseStatus_WalletNotReady, err
}

// Get the list of registered validators
registeredPubkeyMap := map[beacon.ValidatorPubkey]bool{}
pubkeyStatusResponse, err := nc.GetRegisteredValidators(ctx)
// Fetch status from Nodeset APIs
nodesetStatusResponse, err := nc.GetRegisteredValidators(ctx)
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error getting registered validators: %w", err)
return types.ResponseStatus_Error, fmt.Errorf("error getting registered validators from Nodeset: %w", err)
}
registeredPubkeys := []beacon.ValidatorPubkey{}
for _, pubkeyStatus := range pubkeyStatusResponse {
registeredPubkeys = append(registeredPubkeys, pubkeyStatus.Pubkey)

// Fetch private keys and derive public keys
privateKeys, err := w.GetAllPrivateKeys()
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error getting private keys: %w", err)
}
for _, pubkey := range registeredPubkeys {
registeredPubkeyMap[pubkey] = true

privateKeyMap := make(map[beacon.ValidatorPubkey]*eth2types.BLSPrivateKey)
publicKeyMap := make(map[beacon.ValidatorPubkey]bool)
publicKeys := []beacon.ValidatorPubkey{}
for _, privateKey := range privateKeys {
pubkey := beacon.ValidatorPubkey(privateKey.PublicKey().Marshal())
publicKeys = append(publicKeys, pubkey)
publicKeyMap[pubkey] = true
privateKeyMap[pubkey] = privateKey
}

// Get the list of this node's validator keys
keys, err := w.GetAllPrivateKeys()
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error getting private validator keys: %w", err)
activePubkeysOnNodeset := []beacon.ValidatorPubkey{}
pendingPubkeysOnNodeset := []beacon.ValidatorPubkey{}

for _, validator := range nodesetStatusResponse {
_, exists := publicKeyMap[validator.Pubkey]
if exists {
if validator.Status != pendingState {
activePubkeysOnNodeset = append(activePubkeysOnNodeset, validator.Pubkey)
} else {
pendingPubkeysOnNodeset = append(pendingPubkeysOnNodeset, validator.Pubkey)
}
}
}
data.TotalCount = uint64(len(keys))

// Find the ones that haven't been uploaded yet
// Process public keys based on their status
unregisteredKeys := []*eth2types.BLSPrivateKey{}
newPubkeys := []beacon.ValidatorPubkey{}
for _, key := range keys {
pubkey := beacon.ValidatorPubkey(key.PublicKey().Marshal())
_, exists := registeredPubkeyMap[pubkey]
if !exists {
unregisteredKeys = append(unregisteredKeys, key)
newPubkeys = append(newPubkeys, pubkey)
data.TotalCount = uint64(len(publicKeys)) - uint64(len(pendingPubkeysOnNodeset))
// Used for displaying the unregistered keys in the response
unregisteredPubkeys := []beacon.ValidatorPubkey{}

for _, pubkey := range publicKeys {
if !swcommon.IsUploadedToNodeset(pubkey, activePubkeysOnNodeset) && !swcommon.IsUploadedToNodeset(pubkey, pendingPubkeysOnNodeset) {
unregisteredKeys = append(unregisteredKeys, privateKeyMap[pubkey])
unregisteredPubkeys = append(unregisteredPubkeys, pubkey)
}
}
data.UnregisteredPubkeys = newPubkeys

if len(unregisteredKeys) == 0 {
return types.ResponseStatus_Success, nil
// Determine if sufficient balance is available for deposits
balance, err := ec.BalanceAt(ctx, opts.From, nil)
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error getting balance: %w", err)
}
data.Balance = eth.WeiToEth(balance)

// Make sure validator has enough funds to pay for the deposit
if !c.bypassBalanceCheck {
balance, err := ec.BalanceAt(ctx, opts.From, nil)
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error getting balance: %w", err)
}
data.Balance = balance
totalCost := big.NewInt(0)
costPerKey := eth.EthToWei(validatorDepositCost)

unregisteredKeysCount := len(unregisteredKeys)
pendingPubkeysOnNodesetCount := len(pendingPubkeysOnNodeset)

totalCost := big.NewInt(int64(len(unregisteredKeys)))
totalCost.Mul(totalCost, eth.EthToWei(0.01))
data.RequiredBalance = totalCost
totalCostForKeys := big.NewInt(0).Mul(costPerKey, big.NewInt(int64(unregisteredKeysCount+pendingPubkeysOnNodesetCount)))
totalCost.Add(totalCost, totalCostForKeys)

data.SufficientBalance = (totalCost.Cmp(balance) < 0)
if !data.SufficientBalance {
return types.ResponseStatus_Success, nil
data.SufficientBalance = (totalCost.Cmp(balance) <= 0)

if !data.SufficientBalance {
for totalCost.Cmp(balance) > 0 {
unregisteredKeys = unregisteredKeys[1:]
unregisteredPubkeys = unregisteredPubkeys[1:]
totalCost.Sub(totalCost, costPerKey)
}
data.UnregisteredPubkeys = unregisteredPubkeys
}

remainingKeys := uint64(len(publicKeys)) - uint64(len(data.UnregisteredPubkeys)) - uint64(len(pendingPubkeysOnNodeset))
remainingCost := big.NewInt(0)
if remainingKeys > 0 {
remainingCost = big.NewInt(0).Mul(costPerKey, big.NewInt(int64(remainingKeys)))
}
data.RemainingEthRequired = eth.WeiToEth(remainingCost)

// Get the deposit data for those pubkeys
if len(unregisteredKeys) == 0 {
return types.ResponseStatus_Success, nil
}
// Generate deposit data and submit
depositData, err := ddMgr.GenerateDepositData(unregisteredKeys)
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error generating deposit data: %w", err)
}

// Serialize it
bytes, err := json.Marshal(depositData)
serializedData, err := json.Marshal(depositData)
if err != nil {
return types.ResponseStatus_Error, fmt.Errorf("error serializing deposit data: %w", err)
}

// Submit the upload
response, err := nc.UploadDepositData(ctx, bytes)
if err != nil {
if response, err := nc.UploadDepositData(ctx, serializedData); err != nil {
return types.ResponseStatus_Error, err
} else {
data.ServerResponse = response
}
data.ServerResponse = response

return types.ResponseStatus_Success, nil
}
27 changes: 5 additions & 22 deletions server/status/get-validator-statuses.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"fmt"
"net/url"

swcommon "github.com/nodeset-org/hyperdrive-stakewise/common"
swapi "github.com/nodeset-org/hyperdrive-stakewise/shared/api"
swtypes "github.com/nodeset-org/hyperdrive-stakewise/shared/types"

"github.com/rocket-pool/node-manager-core/api/types"
"github.com/rocket-pool/node-manager-core/beacon"
"github.com/rocket-pool/node-manager-core/wallet"
Expand Down Expand Up @@ -100,11 +102,11 @@ func (c *statusGetValidatorsStatusesContext) PrepareData(data *swapi.ValidatorSt

// NodeSet status
switch {
case isRegisteredToStakewise(pubkey, beaconStatusResponse):
case swcommon.IsRegisteredToStakewise(pubkey, beaconStatusResponse):
state.NodesetStatus = swtypes.NodesetStatus_RegisteredToStakewise
case isUploadedStakewise(pubkey, beaconStatusResponse):
case swcommon.IsUploadedStakewise(pubkey, beaconStatusResponse):
state.NodesetStatus = swtypes.NodesetStatus_UploadedStakewise
case isUploadedToNodeset(pubkey, registeredPubkeys):
case swcommon.IsUploadedToNodeset(pubkey, registeredPubkeys):
state.NodesetStatus = swtypes.NodesetStatus_UploadedToNodeset
default:
state.NodesetStatus = swtypes.NodesetStatus_Generated
Expand All @@ -113,22 +115,3 @@ func (c *statusGetValidatorsStatusesContext) PrepareData(data *swapi.ValidatorSt

return types.ResponseStatus_Success, nil
}

func isRegisteredToStakewise(pubKey beacon.ValidatorPubkey, statuses map[beacon.ValidatorPubkey]beacon.ValidatorStatus) bool {
// TODO: Implement
return false
}

func isUploadedStakewise(pubKey beacon.ValidatorPubkey, statuses map[beacon.ValidatorPubkey]beacon.ValidatorStatus) bool {
// TODO: Implement
return false
}

func isUploadedToNodeset(pubKey beacon.ValidatorPubkey, registeredPubkeys []beacon.ValidatorPubkey) bool {
for _, registeredPubKey := range registeredPubkeys {
if registeredPubKey == pubKey {
return true
}
}
return false
}
15 changes: 7 additions & 8 deletions shared/api/nodeset.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package swapi

import (
"math/big"

"github.com/rocket-pool/node-manager-core/beacon"
)

type NodesetUploadDepositDataData struct {
SufficientBalance bool `json:"sufficientBalance"`
Balance *big.Int `json:"balance"`
RequiredBalance *big.Int `json:"requiredBalance"`
ServerResponse []byte `json:"serverResponse"`
UnregisteredPubkeys []beacon.ValidatorPubkey `json:"newPubkeys"`
TotalCount uint64 `json:"totalCount"`
SufficientBalance bool `json:"sufficientBalance"`
Balance float64 `json:"balance"`
ServerResponse []byte `json:"serverResponse"`
UnregisteredPubkeys []beacon.ValidatorPubkey `json:"newPubkeys"`
TotalCount uint64 `json:"totalCount"`
EthPerKey float64 `json:"ethPerKey"`
RemainingEthRequired float64 `json:"remainingEthRequired"`
}