Skip to content
Closed
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
33 changes: 33 additions & 0 deletions internal/rpc/jsonrpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"decred.org/dcrwallet/v5/rpc/client/dcrd"
"decred.org/dcrwallet/v5/rpc/jsonrpc/types"
"decred.org/dcrwallet/v5/spv"
"decred.org/dcrwallet/v5/ticketbuyer"
"decred.org/dcrwallet/v5/version"
"decred.org/dcrwallet/v5/wallet"
"decred.org/dcrwallet/v5/wallet/txauthor"
Expand Down Expand Up @@ -153,6 +154,7 @@ var handlers = map[string]handler{
"redeemmultisigouts": {fn: (*Server).redeemMultiSigOuts},
"renameaccount": {fn: (*Server).renameAccount},
"rescanwallet": {fn: (*Server).rescanWallet},
"runaccountmixer": {fn: (*Server).runAccountMixer},
"sendfrom": {fn: (*Server).sendFrom},
"sendfromtreasury": {fn: (*Server).sendFromTreasury},
"sendmany": {fn: (*Server).sendMany},
Expand Down Expand Up @@ -5550,6 +5552,37 @@ func (s *Server) mixOutput(ctx context.Context, icmd any) (any, error) {
return nil, err
}

// runAccountMixer starts a new account mixer for the specified account (and
// branch).
func (s *Server) runAccountMixer(ctx context.Context, icmd any) (any, error) {
cmd := icmd.(*types.RunAccountMixerCmd)
w, ok := s.walletLoader.LoadedWallet()
if !ok {
return nil, errUnloadedWallet
}

tb := ticketbuyer.New(w, ticketbuyer.Config{
Mixing: true,
MixedAccountBranch: cmd.MixedAccountBranch,
MixedAccount: cmd.MixedAccount,
ChangeAccount: cmd.ChangeAccount,
BuyTickets: false,
MixChange: true,
})

// Start ticketbuyer in the background rather than blocking the rpc request.
// Use the server waitgroup to ensure Run can return cleanly rather than
// being killed mid database transaction.
s.wg.Add(1)
go func() {
defer s.wg.Done()
serverCtx := s.httpServer.BaseContext(nil)
_ = tb.Run(serverCtx, []byte(cmd.Passphrase))
}()

return nil, nil
}

func (s *Server) mixAccount(ctx context.Context, icmd any) (any, error) {
if !s.cfg.MixingEnabled {
return nil, errors.E("Mixing is not configured")
Expand Down
3 changes: 2 additions & 1 deletion internal/rpc/jsonrpc/rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func helpDescsEnUS() map[string]string {
"redeemmultisigouts": "redeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\n\nTakes a hash, looks up all unspent outpoints and generates list artially signed transactions spending to either an address specified or internal addresses\n\nArguments:\n1. fromscraddress (string, required) Input script hash address.\n2. toaddress (string, optional) Address to look for (if not internal addresses).\n3. number (numeric, optional) Number of outpoints found.\n\nResult:\n{\n \"hex\": \"value\", (string) Resulting hash.\n \"complete\": true|false, (boolean) Shows if opperation was completed.\n \"errors\": [{ (array of object) Any errors generated.\n \"txid\": \"value\", (string) The transaction hash of the referenced previous output\n \"vout\": n, (numeric) The output index of the referenced previous output\n \"scriptSig\": \"value\", (string) The hex-encoded signature script\n \"sequence\": n, (numeric) Script sequence number\n \"error\": \"value\", (string) Verification or signing error related to the input\n },...], \n} \n",
"renameaccount": "renameaccount \"oldaccount\" \"newaccount\"\n\nRenames an account.\n\nArguments:\n1. oldaccount (string, required) The old account name to rename\n2. newaccount (string, required) The new name for the account\n\nResult:\nNothing\n",
"rescanwallet": "rescanwallet (beginheight=0)\n\nRescan the block chain for wallet data, blocking until the rescan completes or exits with an error\n\nArguments:\n1. beginheight (numeric, optional, default=0) The height of the first block to begin the rescan from\n\nResult:\nNothing\n",
"runaccountmixer": "runaccountmixer \"passphrase\" mixedaccount mixedaccountbranch changeaccount\n\nStarts a new account mixer for the specified account (and branch)\n\nArguments:\n1. passphrase (string, required) The private passphrase to unlock the wallet\n2. mixedaccount (numeric, required) The account number to which the mixing funds should end up\n3. mixedaccountbranch (numeric, required) The branch number to which the mixing funds should end up\n4. changeaccount (numeric, required) The account that will be used for any unmixed change that is waiting to be mixed\n\nResult:\nNothing\n",
"sendfrom": "sendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\n\nAuthors, signs, and sends a transaction that outputs some amount to a payment address.\nA change output is automatically included to send extra output value back to the original account.\n\nArguments:\n1. fromaccount (string, required) Account to pick unspent outputs from\n2. toaddress (string, required) Address to pay\n3. amount (numeric, required) Amount to send to the payment address valued in decred\n4. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction output is eligible to be spent\n5. comment (string, optional) Unused\n6. commentto (string, optional) Unused\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
"sendfromtreasury": "sendfromtreasury \"key\" amounts\n\nSend from treasury balance to multiple recipients.\n\nArguments:\n1. key (string, required) Politeia public key\n2. amounts (object, required) Pairs of payment addresses and the output amount to pay each\n{\n \"Address to pay\": Amount to send to the payment address valued in decred, (object) JSON object using payment addresses as keys and output amounts valued in decred to send to each address\n ...\n}\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
"sendmany": "sendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\n\nAuthors, signs, and sends a transaction that outputs to many payment addresses.\nA change output is automatically included to send extra output value back to the original account.\n\nArguments:\n1. fromaccount (string, required) Account to pick unspent outputs from\n2. amounts (object, required) Pairs of payment addresses and the output amount to pay each\n{\n \"Address to pay\": Amount to send to the payment address valued in decred, (object) JSON object using payment addresses as keys and output amounts valued in decred to send to each address\n ...\n}\n3. minconf (numeric, optional, default=1) Minimum number of block confirmations required before a transaction output is eligible to be spent\n4. comment (string, optional) Unused\n\nResult:\n\"value\" (string) The transaction hash of the sent transaction\n",
Expand Down Expand Up @@ -114,4 +115,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\"\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\" (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\" (minconf=1 numtickets=1 expiry \"comment\" dontsigntx)\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrenameaccount \"oldaccount\" \"newaccount\"\nrescanwallet (beginheight=0)\nrunaccountmixer \"passphrase\" mixedaccount mixedaccountbranch changeaccount\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\""
7 changes: 7 additions & 0 deletions internal/rpchelp/helpdescs_en_US.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,13 @@ var helpDescsEnUS = map[string]string{
"rescanwallet--synopsis": "Rescan the block chain for wallet data, blocking until the rescan completes or exits with an error",
"rescanwallet-beginheight": "The height of the first block to begin the rescan from",

// RunAccountMixerCmd help.
"runaccountmixer--synopsis": "Starts a new account mixer for the specified account (and branch)",
"runaccountmixer-passphrase": "The private passphrase to unlock the wallet",
"runaccountmixer-mixedaccount": "The account number to which the mixing funds should end up",
"runaccountmixer-mixedaccountbranch": "The branch number to which the mixing funds should end up",
"runaccountmixer-changeaccount": "The account that will be used for any unmixed change that is waiting to be mixed",

// SendFromCmd help.
"sendfrom--synopsis": "Authors, signs, and sends a transaction that outputs some amount to a payment address.\n" +
"A change output is automatically included to send extra output value back to the original account.",
Expand Down
3 changes: 2 additions & 1 deletion internal/rpchelp/methods.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2015 The btcsuite developers
// Copyright (c) 2015-2024 The Decred developers
// Copyright (c) 2015-2025 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -97,6 +97,7 @@ var Methods = []struct {
{"redeemmultisigouts", []any{(*types.RedeemMultiSigOutResult)(nil)}},
{"renameaccount", nil},
{"rescanwallet", nil},
{"runaccountmixer", nil},
{"sendfrom", returnsString},
{"sendfromtreasury", returnsString},
{"sendmany", returnsString},
Expand Down
21 changes: 21 additions & 0 deletions rpc/jsonrpc/types/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,26 @@ func NewWalletPassphraseChangeCmd(oldPassphrase, newPassphrase string) *WalletPa
}
}

// RunAccountMixerCmd defines the runaccountmixer JSON-RPC command.
type RunAccountMixerCmd struct {
Passphrase string
MixedAccount uint32
MixedAccountBranch uint32
ChangeAccount uint32
}

// NewRunAccountMixerCmd returns a new instance which can be used to issue a
// runaccountmixer JSON-RPC command.
func NewRunAccountMixerCmd(passphrase string, mixedAccount uint32,
mixedAccountBranch uint32, changeAccount uint32) *RunAccountMixerCmd {
return &RunAccountMixerCmd{
Passphrase: passphrase,
MixedAccount: mixedAccount,
MixedAccountBranch: mixedAccountBranch,
ChangeAccount: changeAccount,
}
}

// MixAccountCmd defines the mixaccount JSON-RPC command.
type MixAccountCmd struct{}

Expand Down Expand Up @@ -1257,6 +1277,7 @@ func init() {
{"redeemmultisigouts", (*RedeemMultiSigOutsCmd)(nil)},
{"renameaccount", (*RenameAccountCmd)(nil)},
{"rescanwallet", (*RescanWalletCmd)(nil)},
{"runaccountmixer", (*RunAccountMixerCmd)(nil)},
{"sendfrom", (*SendFromCmd)(nil)},
{"sendfromtreasury", (*SendFromTreasuryCmd)(nil)},
{"sendmany", (*SendManyCmd)(nil)},
Expand Down
Loading