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

[NEW] Add offline mode #364

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions shared/services/config/rocket-pool-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type RocketPoolConfig struct {

IsNativeMode bool `yaml:"-"`

Offline config.Parameter `yaml:"offline"`
NodeAddress config.Parameter `yaml:"nodeAddress"`

// Execution client settings
ExecutionClientMode config.Parameter `yaml:"executionClientMode,omitempty"`
ExecutionClient config.Parameter `yaml:"executionClient,omitempty"`
Expand Down Expand Up @@ -213,6 +216,30 @@ func NewRocketPoolConfig(rpDir string, isNativeMode bool) *RocketPoolConfig {
}},
},

Offline: config.Parameter{
ID: "offline",
Name: "Offline Mode",
Description: "Enable this if you would like to keep your node operator key offline.",
Type: config.ParameterType_Bool,
Default: map[config.Network]interface{}{config.Network_All: false},
AffectsContainers: []config.ContainerID{config.ContainerID_Api, config.ContainerID_Node},
EnvironmentVariables: []string{},
CanBeBlank: false,
OverwriteOnUpgrade: false,
},

NodeAddress: config.Parameter{
ID: "nodeAddress",
Name: "Node Operator Address",
Description: "The address of the node operator key. Only used in conjunction with offline mode.",
Type: config.ParameterType_String,
Default: map[config.Network]interface{}{config.Network_All: ""},
AffectsContainers: []config.ContainerID{config.ContainerID_Api, config.ContainerID_Node, config.ContainerID_Watchtower},
EnvironmentVariables: []string{},
CanBeBlank: true,
OverwriteOnUpgrade: false,
},

UseFallbackClients: config.Parameter{
ID: "useFallbackClients",
Name: "Use Fallback Clients",
Expand Down Expand Up @@ -527,6 +554,8 @@ func (cfg *RocketPoolConfig) GetParameters() []*config.Parameter {
&cfg.ReconnectDelay,
&cfg.ConsensusClientMode,
&cfg.ConsensusClient,
&cfg.Offline,
&cfg.NodeAddress,
&cfg.ExternalConsensusClient,
&cfg.EnableMetrics,
&cfg.EnableODaoMetrics,
Expand Down
11 changes: 11 additions & 0 deletions shared/services/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ func getWallet(c *cli.Context, cfg *config.RocketPoolConfig, pm *passwords.Passw
return
}

// Offline mode
if cfg.Offline.Value == true {
operatorAddress := cfg.NodeAddress.Value.(string)

if operatorAddress == "" {
fmt.Println("Offline mode enabled, but no operator address specified in config file, skipping offline setup...")
return
}
nodeWallet.SetOffline(operatorAddress)
}

// Keystores
lighthouseKeystore := lhkeystore.NewKeystore(os.ExpandEnv(cfg.Smartnode.GetValidatorKeychainPath()), pm)
lodestarKeystore := lokeystore.NewKeystore(os.ExpandEnv(cfg.Smartnode.GetValidatorKeychainPath()), pm)
Expand Down
26 changes: 26 additions & 0 deletions shared/services/wallet/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package wallet
import (
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"math/big"

"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)

Expand All @@ -21,6 +24,10 @@ func (w *Wallet) GetNodeAccount() (accounts.Account, error) {
return accounts.Account{}, errors.New("Wallet is not initialized")
}

if w.Offline() {
return *w.nodeAddress, nil
}

// Get private key
privateKey, path, err := w.getNodePrivateKey()
if err != nil {
Expand Down Expand Up @@ -53,6 +60,25 @@ func (w *Wallet) GetNodeAccountTransactor() (*bind.TransactOpts, error) {
return nil, errors.New("Wallet is not initialized")
}

if w.Offline() {
var transactor bind.TransactOpts
transactor.From = w.nodeAddress.Address
transactor.Context = context.Background()
transactor.GasFeeCap = w.maxFee
transactor.GasTipCap = w.maxPriorityFee
transactor.GasLimit = w.gasLimit
transactor.Signer = func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
txJSON, err := json.MarshalIndent(tx, "", " ")
if err != nil {
return tx, err
}
fmt.Printf("Offline mode: this transaction would have been signed by %s:\n%s\n", address.String(), string(txJSON))
return nil, fmt.Errorf("Offline mode - transaction not signed")
}

return &transactor, nil
}

// Get private key
privateKey, _, err := w.getNodePrivateKey()
if err != nil {
Expand Down
17 changes: 16 additions & 1 deletion shared/services/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid"
Expand Down Expand Up @@ -39,6 +40,7 @@ type Wallet struct {
pm *passwords.PasswordManager
encryptor *eth2ks.Encryptor
chainID *big.Int
offline bool

// Encrypted store
ws *walletStore
Expand All @@ -48,6 +50,7 @@ type Wallet struct {
mk *hdkeychain.ExtendedKey

// Node key cache
nodeAddress *accounts.Account
nodeKey *ecdsa.PrivateKey
nodeKeyPath string

Expand Down Expand Up @@ -100,6 +103,18 @@ func NewWallet(walletPath string, chainId uint, maxFee *big.Int, maxPriorityFee

}

func (w *Wallet) Offline() bool {
return w.offline
}

// This function designates a wallet as offline
func (w *Wallet) SetOffline(address string) {
w.offline = true
w.nodeAddress = &accounts.Account{
Address: common.HexToAddress(address),
}
}

// Gets the wallet's chain ID
func (w *Wallet) GetChainID() *big.Int {
copy := big.NewInt(0).Set(w.chainID)
Expand All @@ -113,7 +128,7 @@ func (w *Wallet) AddKeystore(name string, ks keystore.Keystore) {

// Check if the wallet has been initialized
func (w *Wallet) IsInitialized() bool {
return (w.ws != nil && w.seed != nil && w.mk != nil)
return w.offline || (w.ws != nil && w.seed != nil && w.mk != nil)
}

// Attempt to initialize the wallet if not initialized and return status
Expand Down