From f1e84cfb3774a5999c86af74ae2814f6d85650d2 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 16 Dec 2024 16:17:49 +0000 Subject: [PATCH] Implement the debuglevel JSON-RPC method This allows debug levels to be made more or less verbose at runtime, without requiring an application restart to change the config. The semantics and usage is identical to dcrd's debuglevel method. --- internal/rpc/jsonrpc/config.go | 15 +++++++++++- internal/rpc/jsonrpc/methods.go | 18 +++++++++++++++ internal/rpc/jsonrpc/rpcserverhelp.go | 3 ++- internal/rpchelp/helpdescs_en_US.go | 5 ++++ internal/rpchelp/methods.go | 1 + log.go | 33 +++++++++++++++++++++++++++ rpc/jsonrpc/types/methods.go | 2 ++ rpcserver.go | 17 ++++++++++++++ 8 files changed, 92 insertions(+), 2 deletions(-) diff --git a/internal/rpc/jsonrpc/config.go b/internal/rpc/jsonrpc/config.go index 51b3f8224..bb1bfa033 100644 --- a/internal/rpc/jsonrpc/config.go +++ b/internal/rpc/jsonrpc/config.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2024 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -29,4 +29,17 @@ type Options struct { VSPPubKey string VSPMaxFee dcrutil.Amount Dial func(ctx context.Context, network, addr string) (net.Conn, error) + + Loggers Loggers +} + +// Loggers provides access to manage all application subsystem loggers. +type Loggers interface { + // Subsystems returns all of the application logging subsystem names. + Subsystems() []string + + // SetLevels sets all loggers, or a specific logger (when levelSpec is + // prefixed by the subsystem and an equals sign) to a particular debug + // level. + SetLevels(levelSpec string) error } diff --git a/internal/rpc/jsonrpc/methods.go b/internal/rpc/jsonrpc/methods.go index e0c8f35b1..5b3227554 100644 --- a/internal/rpc/jsonrpc/methods.go +++ b/internal/rpc/jsonrpc/methods.go @@ -95,6 +95,7 @@ var handlers = map[string]handler{ "createnewaccount": {fn: (*Server).createNewAccount}, "createrawtransaction": {fn: (*Server).createRawTransaction}, "createsignature": {fn: (*Server).createSignature}, + "debuglevel": {fn: (*Server).debugLevel}, "disapprovepercent": {fn: (*Server).disapprovePercent}, "discoverusage": {fn: (*Server).discoverUsage}, "dumpprivkey": {fn: (*Server).dumpPrivKey}, @@ -791,6 +792,23 @@ func (s *Server) createSignature(ctx context.Context, icmd any) (any, error) { }, nil } +func (s *Server) debugLevel(ctx context.Context, icmd any) (any, error) { + cmd := icmd.(*types.DebugLevelCmd) + + if cmd.LevelSpec == "show" { + return fmt.Sprintf("Supported subsystems %v", + s.cfg.Loggers.Subsystems()), nil + } + + err := s.cfg.Loggers.SetLevels(cmd.LevelSpec) + if err != nil { + return nil, rpcErrorf(dcrjson.ErrRPCInvalidParameter, + "invalid debug level %v: %v", cmd.LevelSpec, err) + } + + return "Done.", nil +} + // disapprovePercent returns the wallets current disapprove percentage. func (s *Server) disapprovePercent(ctx context.Context, _ any) (any, error) { w, ok := s.walletLoader.LoadedWallet() diff --git a/internal/rpc/jsonrpc/rpcserverhelp.go b/internal/rpc/jsonrpc/rpcserverhelp.go index 5a6e1d079..be5e20b47 100644 --- a/internal/rpc/jsonrpc/rpcserverhelp.go +++ b/internal/rpc/jsonrpc/rpcserverhelp.go @@ -16,6 +16,7 @@ func helpDescsEnUS() map[string]string { "createnewaccount": "createnewaccount \"account\"\n\nCreates a new account.\nThe wallet must be unlocked for this request to succeed.\n\nArguments:\n1. account (string, required) Name of the new account\n\nResult:\nNothing\n", "createrawtransaction": "createrawtransaction [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...] {\"address\":amount,...} (locktime expiry)\n\nReturns a new transaction spending the provided inputs and sending to the provided addresses.\nThe transaction inputs are not signed in the created transaction.\nThe signrawtransaction RPC command provided by wallet must be used to sign the resulting transaction.\n\nArguments:\n1. inputs (array of object, required) The inputs to the transaction\n[{\n \"amount\": n.nnn, (numeric) The previous output amount\n \"txid\": \"value\", (string) The transaction hash of the referenced output\n \"vout\": n, (numeric) The output index of the referenced output\n \"tree\": n, (numeric) The tree to generate transaction for\n},...]\n2. amounts (object, required) JSON object with the destination addresses as keys and amounts as values\n{\n \"address\": n.nnn, (object) The destination address as the key and the amount in DCR as the value\n ...\n}\n3. locktime (numeric, optional) Locktime value; a non-zero value will also locktime-activate the inputs\n4. expiry (numeric, optional) Expiry value; a non-zero value when the transaction expiry\n\nResult:\n\"value\" (string) Hex-encoded bytes of the serialized transaction\n", "createsignature": "createsignature \"address\" inputindex hashtype \"previouspkscript\" \"serializedtransaction\"\n\nGenerate a signature for a transaction input script.\n\nArguments:\n1. address (string, required) The address of the private key to use to create the signature.\n2. inputindex (numeric, required) The index of the transaction input to sign.\n3. hashtype (numeric, required) The signature hash flags to use.\n4. previouspkscript (string, required) The hex encoded previous output script or P2SH redeem script.\n5. serializedtransaction (string, required) The hex encoded transaction to add input signatures to.\n\nResult:\n{\n \"signature\": \"value\", (string) The hex encoded signature.\n \"publickey\": \"value\", (string) The hex encoded serialized compressed pubkey of the address.\n} \n", + "debuglevel": "debuglevel \"levelspec\"\n\nSet all or per-subsystem application log levels.\n\nArguments:\n1. levelspec (string, required) The log level to set all loggers to, optionally prefixed by a subsystem and equals sign to set a specific subsystem's log level, or 'show' to display all subsystems.\n\nResult:\n\"value\" (string) All available subsytems (when levelspec is 'show'), or 'Done.'\n", "disapprovepercent": "disapprovepercent\n\nReturns the wallet's current block disapprove percent per vote. i.e. 100 means that all votes disapprove the block they are called on. Only used for testing purposes.\n\nArguments:\nNone\n\nResult:\nn (numeric) The disapprove percent. When voting, this percent of votes will randomly disapprove the block they are called on.\n", "discoverusage": "discoverusage (\"startblock\" discoveraccounts gaplimit)\n\nPerform address and/or account discovery\n\nArguments:\n1. startblock (string, optional) Hash of block to begin discovery from, or null to scan from the genesis block\n2. discoveraccounts (boolean, optional) Perform account discovery in addition to address discovery. Requires unlocked wallet.\n3. gaplimit (numeric, optional) Allowed unused address gap.\n\nResult:\nNothing\n", "dumpprivkey": "dumpprivkey \"address\"\n\nReturns the private key in WIF encoding that controls some wallet address.\n\nArguments:\n1. address (string, required) The address to return a private key for\n\nResult:\n\"value\" (string) The WIF-encoded private key\n", @@ -113,4 +114,4 @@ var localeHelpDescs = map[string]func() map[string]string{ "en_US": helpDescsEnUS, } -var requestUsages = "abandontransaction \"hash\"\naccountaddressindex \"account\" branch\naccountsyncaddressindex \"account\" branch index\naccountunlocked \"account\"\naddmultisigaddress nrequired [\"key\",...] (\"account\")\naddtransaction \"blockhash\" \"transaction\"\nauditreuse (since)\nconsolidate inputs (\"account\" \"address\")\ncreatemultisig nrequired [\"key\",...]\ncreatenewaccount \"account\"\ncreaterawtransaction [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...] {\"address\":amount,...} (locktime expiry)\ncreatesignature \"address\" inputindex hashtype \"previouspkscript\" \"serializedtransaction\"\ndisapprovepercent\ndiscoverusage (\"startblock\" discoveraccounts gaplimit)\ndumpprivkey \"address\"\nfundrawtransaction \"hexstring\" \"fundaccount\" ({\"changeaddress\":changeaddress,\"feerate\":feerate,\"conftarget\":conftarget})\ngetaccount \"address\"\ngetaccountaddress \"account\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblock\ngetbestblockhash\ngetblockcount\ngetblockhash index\ngetblockheader \"hash\" (verbose=true)\ngetblock \"hash\" (verbose=true verbosetx=false)\ngetcoinjoinsbyacct\ngetcurrentnet\ngetinfo\ngetmasterpubkey (\"account\")\ngetmultisigoutinfo \"hash\" index\ngetnewaddress (\"account\" \"gappolicy\")\ngetpeerinfo\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngetstakeinfo\ngettickets includeimmature\ngettransaction \"txid\" (includewatchonly=false)\ngettxout \"txid\" vout tree (includemempool=true)\ngetunconfirmedbalance (\"account\")\ngetvotechoices (\"tickethash\")\ngetwalletfee\ngetcfilterv2 \"blockhash\"\nhelp (\"command\")\nimportcfiltersv2 startheight [\"filter\",...]\nimportprivkey \"privkey\" (\"label\" rescan=true scanfrom)\nimportpubkey \"pubkey\" (\"label\" rescan=true scanfrom)\nimportscript \"hex\" (rescan=true scanfrom)\nimportxpub \"name\" \"xpub\"\nlistaccounts (minconf=1)\nlistaddresstransactions [\"address\",...] (\"account\")\nlistalltransactions (\"account\")\nlistlockunspent (\"account\")\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (\"account\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...] \"account\")\nlockaccount \"account\"\nlockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\nmixaccount\nmixoutput \"outpoint\"\nprocessunmanagedticket \"tickethash\"\npurchaseticket \"fromaccount\" spendlimit (minconf=1 numtickets=1 expiry \"comment\" dontsigntx)\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrenameaccount \"oldaccount\" \"newaccount\"\nrescanwallet (beginheight=0)\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendfromtreasury \"key\" amounts\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendrawtransaction \"hextx\" (allowhighfees=false)\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsendtomultisig \"fromaccount\" amount [\"pubkey\",...] (nrequired=1 minconf=1 \"comment\")\nsendtotreasury amount\nsetaccountpassphrase \"account\" \"passphrase\"\nsetdisapprovepercent percent\nsettreasurypolicy \"key\" \"policy\" (\"ticket\")\nsettspendpolicy \"hash\" \"policy\" (\"ticket\")\nsettxfee amount\nsetvotechoice \"agendaid\" \"choiceid\" (\"tickethash\")\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"tree\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nsignrawtransactions [\"rawtx\",...] (send=true)\nspendoutputs \"account\" [\"previousoutpoint\",...] [{\"address\":\"value\",\"amount\":n.nnn},...]\nsweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\nsyncstatus\nticketinfo (startheight=0)\ntreasurypolicy (\"key\" \"ticket\")\ntspendpolicy (\"hash\" \"ticket\")\nunlockaccount \"account\" \"passphrase\"\nvalidateaddress \"address\"\nvalidatepredcp0005cf\nverifymessage \"address\" \"signature\" \"message\"\nversion\nwalletinfo\nwalletislocked\nwalletlock\nwalletpassphrase \"passphrase\" timeout\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\nwalletpubpassphrasechange \"oldpassphrase\" \"newpassphrase\"" +var requestUsages = "abandontransaction \"hash\"\naccountaddressindex \"account\" branch\naccountsyncaddressindex \"account\" branch index\naccountunlocked \"account\"\naddmultisigaddress nrequired [\"key\",...] (\"account\")\naddtransaction \"blockhash\" \"transaction\"\nauditreuse (since)\nconsolidate inputs (\"account\" \"address\")\ncreatemultisig nrequired [\"key\",...]\ncreatenewaccount \"account\"\ncreaterawtransaction [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...] {\"address\":amount,...} (locktime expiry)\ncreatesignature \"address\" inputindex hashtype \"previouspkscript\" \"serializedtransaction\"\ndebuglevel \"levelspec\"\ndisapprovepercent\ndiscoverusage (\"startblock\" discoveraccounts gaplimit)\ndumpprivkey \"address\"\nfundrawtransaction \"hexstring\" \"fundaccount\" ({\"changeaddress\":changeaddress,\"feerate\":feerate,\"conftarget\":conftarget})\ngetaccount \"address\"\ngetaccountaddress \"account\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblock\ngetbestblockhash\ngetblockcount\ngetblockhash index\ngetblockheader \"hash\" (verbose=true)\ngetblock \"hash\" (verbose=true verbosetx=false)\ngetcoinjoinsbyacct\ngetcurrentnet\ngetinfo\ngetmasterpubkey (\"account\")\ngetmultisigoutinfo \"hash\" index\ngetnewaddress (\"account\" \"gappolicy\")\ngetpeerinfo\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngetstakeinfo\ngettickets includeimmature\ngettransaction \"txid\" (includewatchonly=false)\ngettxout \"txid\" vout tree (includemempool=true)\ngetunconfirmedbalance (\"account\")\ngetvotechoices (\"tickethash\")\ngetwalletfee\ngetcfilterv2 \"blockhash\"\nhelp (\"command\")\nimportcfiltersv2 startheight [\"filter\",...]\nimportprivkey \"privkey\" (\"label\" rescan=true scanfrom)\nimportpubkey \"pubkey\" (\"label\" rescan=true scanfrom)\nimportscript \"hex\" (rescan=true scanfrom)\nimportxpub \"name\" \"xpub\"\nlistaccounts (minconf=1)\nlistaddresstransactions [\"address\",...] (\"account\")\nlistalltransactions (\"account\")\nlistlockunspent (\"account\")\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (\"account\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...] \"account\")\nlockaccount \"account\"\nlockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\nmixaccount\nmixoutput \"outpoint\"\nprocessunmanagedticket \"tickethash\"\npurchaseticket \"fromaccount\" spendlimit (minconf=1 numtickets=1 expiry \"comment\" dontsigntx)\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrenameaccount \"oldaccount\" \"newaccount\"\nrescanwallet (beginheight=0)\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendfromtreasury \"key\" amounts\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendrawtransaction \"hextx\" (allowhighfees=false)\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsendtomultisig \"fromaccount\" amount [\"pubkey\",...] (nrequired=1 minconf=1 \"comment\")\nsendtotreasury amount\nsetaccountpassphrase \"account\" \"passphrase\"\nsetdisapprovepercent percent\nsettreasurypolicy \"key\" \"policy\" (\"ticket\")\nsettspendpolicy \"hash\" \"policy\" (\"ticket\")\nsettxfee amount\nsetvotechoice \"agendaid\" \"choiceid\" (\"tickethash\")\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"tree\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nsignrawtransactions [\"rawtx\",...] (send=true)\nspendoutputs \"account\" [\"previousoutpoint\",...] [{\"address\":\"value\",\"amount\":n.nnn},...]\nsweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\nsyncstatus\nticketinfo (startheight=0)\ntreasurypolicy (\"key\" \"ticket\")\ntspendpolicy (\"hash\" \"ticket\")\nunlockaccount \"account\" \"passphrase\"\nvalidateaddress \"address\"\nvalidatepredcp0005cf\nverifymessage \"address\" \"signature\" \"message\"\nversion\nwalletinfo\nwalletislocked\nwalletlock\nwalletpassphrase \"passphrase\" timeout\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\nwalletpubpassphrasechange \"oldpassphrase\" \"newpassphrase\"" diff --git a/internal/rpchelp/helpdescs_en_US.go b/internal/rpchelp/helpdescs_en_US.go index 796b838c9..f6edb0214 100644 --- a/internal/rpchelp/helpdescs_en_US.go +++ b/internal/rpchelp/helpdescs_en_US.go @@ -97,6 +97,11 @@ var helpDescsEnUS = map[string]string{ "createsignature-hashtype": "The signature hash flags to use.", "createsignature-previouspkscript": "The hex encoded previous output script or P2SH redeem script.", + // DebugLevelCmd help. + "debuglevel--synopsis": "Set all or per-subsystem application log levels.", + "debuglevel-levelspec": "The log level to set all loggers to, optionally prefixed by a subsystem and equals sign to set a specific subsystem's log level, or 'show' to display all subsystems.", + "debuglevel--result0": "All available subsytems (when levelspec is 'show'), or 'Done.'", + // DisapprovePercentCmd help. "disapprovepercent--synopsis": "Returns the wallet's current block disapprove percent per vote. i.e. 100 means that all votes disapprove the block they are called on. Only used for testing purposes.", "disapprovepercent--result0": "The disapprove percent. When voting, this percent of votes will randomly disapprove the block they are called on.", diff --git a/internal/rpchelp/methods.go b/internal/rpchelp/methods.go index b7c8954f3..bf7ac36d3 100644 --- a/internal/rpchelp/methods.go +++ b/internal/rpchelp/methods.go @@ -39,6 +39,7 @@ var Methods = []struct { {"createnewaccount", nil}, {"createrawtransaction", returnsString}, {"createsignature", []any{(*types.CreateSignatureResult)(nil)}}, + {"debuglevel", returnsString}, {"disapprovepercent", []any{(*uint32)(nil)}}, {"discoverusage", nil}, {"dumpprivkey", returnsString}, diff --git a/log.go b/log.go index b6e205bd9..bd2837a22 100644 --- a/log.go +++ b/log.go @@ -7,8 +7,10 @@ package main import ( "os" + "strings" "decred.org/dcrwallet/v5/chain" + "decred.org/dcrwallet/v5/errors" "decred.org/dcrwallet/v5/internal/loader" "decred.org/dcrwallet/v5/internal/loggers" "decred.org/dcrwallet/v5/internal/rpc/jsonrpc" @@ -83,6 +85,37 @@ func setLogLevels(logLevel string) { } } +// setLogLevelSpec sets all loggers, or a specific logger (when levelSpec is +// prefixed by the subsystem and an equals sign) to a particular log level. +func setLogLevelSpec(levelSpec string) error { + var subsys, level string + + equals := strings.Index(levelSpec, "=") + if equals != -1 { + subsys = levelSpec[:equals] + level = levelSpec[equals+1:] + } else { + level = levelSpec + } + + if subsys != "" { + if _, ok := subsystemLoggers[subsys]; !ok { + return errors.Errorf("subsystem %q does not exist", subsys) + } + } + + if _, ok := slog.LevelFromString(level); !ok { + return errors.Errorf("%q is not a valid log level", level) + } + + if subsys != "" { + setLogLevel(subsys, level) + } else { + setLogLevels(level) + } + return nil +} + // fatalf logs a message, flushes the logger, and finally exit the process with // a non-zero return code. func fatalf(format string, args ...any) { diff --git a/rpc/jsonrpc/types/methods.go b/rpc/jsonrpc/types/methods.go index 430ab1b06..711c0857b 100644 --- a/rpc/jsonrpc/types/methods.go +++ b/rpc/jsonrpc/types/methods.go @@ -1306,6 +1306,7 @@ func init() { // dcrd methods also implemented by dcrwallet register = []registeredMethod{ {"createrawtransaction", (*CreateRawTransactionCmd)(nil)}, + {"debuglevel", (*DebugLevelCmd)(nil)}, {"getbestblock", (*GetBestBlockCmd)(nil)}, {"getbestblockhash", (*GetBestBlockHashCmd)(nil)}, {"getblockcount", (*GetBlockCountCmd)(nil)}, @@ -1341,6 +1342,7 @@ func init() { type ( AuthenticateCmd dcrdtypes.AuthenticateCmd CreateRawTransactionCmd dcrdtypes.CreateRawTransactionCmd + DebugLevelCmd dcrdtypes.DebugLevelCmd GetBestBlockCmd dcrdtypes.GetBestBlockCmd GetBestBlockHashCmd dcrdtypes.GetBestBlockHashCmd GetBlockCountCmd dcrdtypes.GetBlockCountCmd diff --git a/rpcserver.go b/rpcserver.go index 6e3870f90..890c48370 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -18,6 +18,7 @@ import ( "os" "path/filepath" "runtime" + "sort" "strings" "time" @@ -229,6 +230,21 @@ func generateClientKeyPair(caPriv any, ca *x509.Certificate) (cert, key []byte, return cert, key, nil } +type rpcLoggers struct{} + +func (rpcLoggers) Subsystems() []string { + s := make([]string, 0, len(subsystemLoggers)) + for name := range subsystemLoggers { + s = append(s, name) + } + sort.Strings(s) + return s +} + +func (rpcLoggers) SetLevels(levelSpec string) error { + return setLogLevelSpec(levelSpec) +} + func startRPCServers(walletLoader *loader.Loader) (*grpc.Server, *jsonrpc.Server, error) { var jsonrpcAddrNotifier jsonrpcListenerEventServer var grpcAddrNotifier grpcListenerEventServer @@ -366,6 +382,7 @@ func startRPCServers(walletLoader *loader.Loader) (*grpc.Server, *jsonrpc.Server VSPMaxFee: cfg.VSPOpts.MaxFee.Amount, TicketSplitAccount: cfg.TicketSplitAccount, Dial: cfg.dial, + Loggers: rpcLoggers{}, } jsonrpcServer = jsonrpc.NewServer(&opts, activeNet.Params, walletLoader, listeners) for _, lis := range listeners {