Skip to content

Commit 21b3400

Browse files
holimanfjl
andcommitted
all: remove personal RPC namespace (#30704)
This PR is a first step towards removing account management from geth, and contains a lot of the user-facing changes. With this PR, the `personal` namespace disappears. **Note**: `personal` namespace has been deprecated for quite some time (since #26390 1 year and 8 months ago), and users who have wanted to use it has been forced to used the flag `--rpc.enabledeprecatedpersonal`. So I think it's fairly non-controversial to drop it at this point. Specifically, this means: - Account/wallet listing -`personal.getListAccounts` -`personal.listAccounts` -`personal.getListWallets` -`personal.listWallets` - Lock/unlock -`personal.lockAccount` -`personal.openWallet` -`personal.unlockAccount` - Sign ops -`personal.sign` -`personal.sendTransaction` -`personal.signTransaction` - Imports / inits -`personal.deriveAccount` -`personal.importRawKey` -`personal.initializeWallet` -`personal.newAccount` -`personal.unpair` - Other: -`personal.ecRecover` The underlying keystores and account managent code is still in place, which means that `geth --dev` still works as expected, so that e.g. the example below still works: ``` > eth.sendTransaction({data:"0x6060", value: 1, from:eth.accounts[0]}) ``` Also, `ethkey` and `clef` are untouched. With the removal of `personal`, as far as I know we have no more API methods which contain credentials, and if we want to implement logging-capabilities of RPC ingress payload, it would be possible after this. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
1 parent 7502503 commit 21b3400

File tree

13 files changed

+20
-774
lines changed

13 files changed

+20
-774
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ var (
6767
utils.SmartCardDaemonPathFlag,
6868
utils.OverrideCancun,
6969
utils.OverrideVerkle,
70-
utils.EnablePersonal,
70+
utils.EnablePersonal, // deprecated
7171
utils.TxPoolLocalsFlag,
7272
utils.TxPoolNoLocalsFlag,
7373
utils.TxPoolJournalFlag,

cmd/utils/flags.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -734,11 +734,6 @@ var (
734734
Value: node.DefaultConfig.BatchResponseMaxSize,
735735
Category: flags.APICategory,
736736
}
737-
EnablePersonal = &cli.BoolFlag{
738-
Name: "rpc.enabledeprecatedpersonal",
739-
Usage: "Enables the (deprecated) personal namespace",
740-
Category: flags.APICategory,
741-
}
742737

743738
// Network Settings
744739
MaxPeersFlag = &cli.IntFlag{
@@ -1392,9 +1387,8 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
13921387
if ctx.IsSet(JWTSecretFlag.Name) {
13931388
cfg.JWTSecret = ctx.String(JWTSecretFlag.Name)
13941389
}
1395-
13961390
if ctx.IsSet(EnablePersonal.Name) {
1397-
cfg.EnablePersonal = true
1391+
log.Warn(fmt.Sprintf("Option --%s is deprecated. The 'personal' RPC namespace has been removed.", EnablePersonal.Name))
13981392
}
13991393

14001394
if ctx.IsSet(ExternalSignerFlag.Name) {

cmd/utils/flags_legacy.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ var (
153153
Usage: "Enable expensive metrics collection and reporting (deprecated)",
154154
Category: flags.DeprecatedCategory,
155155
}
156+
// Deprecated Oct 2024
157+
EnablePersonal = &cli.BoolFlag{
158+
Name: "rpc.enabledeprecatedpersonal",
159+
Usage: "This used to enable the 'personal' namespace.",
160+
Category: flags.DeprecatedCategory,
161+
}
156162
)
157163

158164
// showDeprecated displays deprecated flags that will be soon removed from the codebase.

console/bridge.go

Lines changed: 0 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,12 @@ package console
1919
import (
2020
"encoding/json"
2121
"errors"
22-
"fmt"
2322
"io"
2423
"reflect"
2524
"strings"
2625
"time"
2726

2827
"github.com/dop251/goja"
29-
"github.com/ethereum/go-ethereum/accounts/scwallet"
30-
"github.com/ethereum/go-ethereum/accounts/usbwallet"
3128
"github.com/ethereum/go-ethereum/common/hexutil"
3229
"github.com/ethereum/go-ethereum/console/prompt"
3330
"github.com/ethereum/go-ethereum/internal/jsre"
@@ -51,268 +48,6 @@ func newBridge(client *rpc.Client, prompter prompt.UserPrompter, printer io.Writ
5148
}
5249
}
5350

54-
func getJeth(vm *goja.Runtime) *goja.Object {
55-
jeth := vm.Get("jeth")
56-
if jeth == nil {
57-
panic(vm.ToValue("jeth object does not exist"))
58-
}
59-
return jeth.ToObject(vm)
60-
}
61-
62-
// NewAccount is a wrapper around the personal.newAccount RPC method that uses a
63-
// non-echoing password prompt to acquire the passphrase and executes the original
64-
// RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
65-
func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) {
66-
var (
67-
password string
68-
confirm string
69-
err error
70-
)
71-
switch {
72-
// No password was specified, prompt the user for it
73-
case len(call.Arguments) == 0:
74-
if password, err = b.prompter.PromptPassword("Passphrase: "); err != nil {
75-
return nil, err
76-
}
77-
if confirm, err = b.prompter.PromptPassword("Repeat passphrase: "); err != nil {
78-
return nil, err
79-
}
80-
if password != confirm {
81-
return nil, errors.New("passwords don't match")
82-
}
83-
// A single string password was specified, use that
84-
case len(call.Arguments) == 1 && call.Argument(0).ToString() != nil:
85-
password = call.Argument(0).ToString().String()
86-
default:
87-
return nil, errors.New("expected 0 or 1 string argument")
88-
}
89-
// Password acquired, execute the call and return
90-
newAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("newAccount"))
91-
if !callable {
92-
return nil, errors.New("jeth.newAccount is not callable")
93-
}
94-
ret, err := newAccount(goja.Null(), call.VM.ToValue(password))
95-
if err != nil {
96-
return nil, err
97-
}
98-
return ret, nil
99-
}
100-
101-
// OpenWallet is a wrapper around personal.openWallet which can interpret and
102-
// react to certain error messages, such as the Trezor PIN matrix request.
103-
func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) {
104-
// Make sure we have a wallet specified to open
105-
if call.Argument(0).ToObject(call.VM).ClassName() != "String" {
106-
return nil, errors.New("first argument must be the wallet URL to open")
107-
}
108-
wallet := call.Argument(0)
109-
110-
var passwd goja.Value
111-
if goja.IsUndefined(call.Argument(1)) || goja.IsNull(call.Argument(1)) {
112-
passwd = call.VM.ToValue("")
113-
} else {
114-
passwd = call.Argument(1)
115-
}
116-
// Open the wallet and return if successful in itself
117-
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
118-
if !callable {
119-
return nil, errors.New("jeth.openWallet is not callable")
120-
}
121-
val, err := openWallet(goja.Null(), wallet, passwd)
122-
if err == nil {
123-
return val, nil
124-
}
125-
126-
// Wallet open failed, report error unless it's a PIN or PUK entry
127-
switch {
128-
case strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()):
129-
val, err = b.readPinAndReopenWallet(call)
130-
if err == nil {
131-
return val, nil
132-
}
133-
val, err = b.readPassphraseAndReopenWallet(call)
134-
if err != nil {
135-
return nil, err
136-
}
137-
138-
case strings.HasSuffix(err.Error(), scwallet.ErrPairingPasswordNeeded.Error()):
139-
// PUK input requested, fetch from the user and call open again
140-
input, err := b.prompter.PromptPassword("Please enter the pairing password: ")
141-
if err != nil {
142-
return nil, err
143-
}
144-
passwd = call.VM.ToValue(input)
145-
if val, err = openWallet(goja.Null(), wallet, passwd); err != nil {
146-
if !strings.HasSuffix(err.Error(), scwallet.ErrPINNeeded.Error()) {
147-
return nil, err
148-
}
149-
// PIN input requested, fetch from the user and call open again
150-
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
151-
if err != nil {
152-
return nil, err
153-
}
154-
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(input)); err != nil {
155-
return nil, err
156-
}
157-
}
158-
159-
case strings.HasSuffix(err.Error(), scwallet.ErrPINUnblockNeeded.Error()):
160-
// PIN unblock requested, fetch PUK and new PIN from the user
161-
var pukpin string
162-
input, err := b.prompter.PromptPassword("Please enter current PUK: ")
163-
if err != nil {
164-
return nil, err
165-
}
166-
pukpin = input
167-
input, err = b.prompter.PromptPassword("Please enter new PIN: ")
168-
if err != nil {
169-
return nil, err
170-
}
171-
pukpin += input
172-
173-
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(pukpin)); err != nil {
174-
return nil, err
175-
}
176-
177-
case strings.HasSuffix(err.Error(), scwallet.ErrPINNeeded.Error()):
178-
// PIN input requested, fetch from the user and call open again
179-
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
180-
if err != nil {
181-
return nil, err
182-
}
183-
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(input)); err != nil {
184-
return nil, err
185-
}
186-
187-
default:
188-
// Unknown error occurred, drop to the user
189-
return nil, err
190-
}
191-
return val, nil
192-
}
193-
194-
func (b *bridge) readPassphraseAndReopenWallet(call jsre.Call) (goja.Value, error) {
195-
wallet := call.Argument(0)
196-
input, err := b.prompter.PromptPassword("Please enter your passphrase: ")
197-
if err != nil {
198-
return nil, err
199-
}
200-
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
201-
if !callable {
202-
return nil, errors.New("jeth.openWallet is not callable")
203-
}
204-
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
205-
}
206-
207-
func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) {
208-
wallet := call.Argument(0)
209-
// Trezor PIN matrix input requested, display the matrix to the user and fetch the data
210-
fmt.Fprintf(b.printer, "Look at the device for number positions\n\n")
211-
fmt.Fprintf(b.printer, "7 | 8 | 9\n")
212-
fmt.Fprintf(b.printer, "--+---+--\n")
213-
fmt.Fprintf(b.printer, "4 | 5 | 6\n")
214-
fmt.Fprintf(b.printer, "--+---+--\n")
215-
fmt.Fprintf(b.printer, "1 | 2 | 3\n\n")
216-
217-
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
218-
if err != nil {
219-
return nil, err
220-
}
221-
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
222-
if !callable {
223-
return nil, errors.New("jeth.openWallet is not callable")
224-
}
225-
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
226-
}
227-
228-
// UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
229-
// uses a non-echoing password prompt to acquire the passphrase and executes the
230-
// original RPC method (saved in jeth.unlockAccount) with it to actually execute
231-
// the RPC call.
232-
func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
233-
if len(call.Arguments) < 1 {
234-
return nil, errors.New("usage: unlockAccount(account, [ password, duration ])")
235-
}
236-
237-
account := call.Argument(0)
238-
// Make sure we have an account specified to unlock.
239-
if goja.IsUndefined(account) || goja.IsNull(account) || account.ExportType().Kind() != reflect.String {
240-
return nil, errors.New("first argument must be the account to unlock")
241-
}
242-
243-
// If password is not given or is the null value, prompt the user for it.
244-
var passwd goja.Value
245-
if goja.IsUndefined(call.Argument(1)) || goja.IsNull(call.Argument(1)) {
246-
fmt.Fprintf(b.printer, "Unlock account %s\n", account)
247-
input, err := b.prompter.PromptPassword("Passphrase: ")
248-
if err != nil {
249-
return nil, err
250-
}
251-
passwd = call.VM.ToValue(input)
252-
} else {
253-
if call.Argument(1).ExportType().Kind() != reflect.String {
254-
return nil, errors.New("password must be a string")
255-
}
256-
passwd = call.Argument(1)
257-
}
258-
259-
// Third argument is the duration how long the account should be unlocked.
260-
duration := goja.Null()
261-
if !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
262-
if !isNumber(call.Argument(2)) {
263-
return nil, errors.New("unlock duration must be a number")
264-
}
265-
duration = call.Argument(2)
266-
}
267-
268-
// Send the request to the backend and return.
269-
unlockAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("unlockAccount"))
270-
if !callable {
271-
return nil, errors.New("jeth.unlockAccount is not callable")
272-
}
273-
return unlockAccount(goja.Null(), account, passwd, duration)
274-
}
275-
276-
// Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
277-
// prompt to acquire the passphrase and executes the original RPC method (saved in
278-
// jeth.sign) with it to actually execute the RPC call.
279-
func (b *bridge) Sign(call jsre.Call) (goja.Value, error) {
280-
if nArgs := len(call.Arguments); nArgs < 2 {
281-
return nil, errors.New("usage: sign(message, account, [ password ])")
282-
}
283-
var (
284-
message = call.Argument(0)
285-
account = call.Argument(1)
286-
passwd = call.Argument(2)
287-
)
288-
289-
if goja.IsUndefined(message) || message.ExportType().Kind() != reflect.String {
290-
return nil, errors.New("first argument must be the message to sign")
291-
}
292-
if goja.IsUndefined(account) || account.ExportType().Kind() != reflect.String {
293-
return nil, errors.New("second argument must be the account to sign with")
294-
}
295-
296-
// if the password is not given or null ask the user and ensure password is a string
297-
if goja.IsUndefined(passwd) || goja.IsNull(passwd) {
298-
fmt.Fprintf(b.printer, "Give password for account %s\n", account)
299-
input, err := b.prompter.PromptPassword("Password: ")
300-
if err != nil {
301-
return nil, err
302-
}
303-
passwd = call.VM.ToValue(input)
304-
} else if passwd.ExportType().Kind() != reflect.String {
305-
return nil, errors.New("third argument must be the password to unlock the account")
306-
}
307-
308-
// Send the request to the backend and return
309-
sign, callable := goja.AssertFunction(getJeth(call.VM).Get("sign"))
310-
if !callable {
311-
return nil, errors.New("jeth.sign is not callable")
312-
}
313-
return sign(goja.Null(), message, account, passwd)
314-
}
315-
31651
// Sleep will block the console for the specified number of seconds.
31752
func (b *bridge) Sleep(call jsre.Call) (goja.Value, error) {
31853
if nArgs := len(call.Arguments); nArgs < 1 {

console/bridge_test.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)