Skip to content

Commit

Permalink
multi: implement removeimported rpc.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnldd committed Aug 27, 2019
1 parent 6227901 commit f10ffde
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 4 deletions.
4 changes: 4 additions & 0 deletions internal/rpchelp/helpdescs_en_US.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,10 @@ var helpDescsEnUS = map[string]string{
"redeemmultisigouts-toaddress": "Address to look for (if not internal addresses).",
"redeemmultisigouts-fromscraddress": "Input script hash address.",

// RemoveImported help.
"removeimported--synopsis": "Removes the provided imported script or private key from the wallet.",
"removeimported-data": "The imported script or private key to remove.",

// RescanWallet help.
"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",
Expand Down
1 change: 1 addition & 0 deletions internal/rpchelp/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ var Methods = []struct {
{"redeemmultisigout", []interface{}{(*types.RedeemMultiSigOutResult)(nil)}},
{"redeemmultisigouts", []interface{}{(*types.RedeemMultiSigOutResult)(nil)}},
{"renameaccount", nil},
{"removeimported", nil},
{"rescanwallet", nil},
{"revoketickets", nil},
{"sendfrom", returnsString},
Expand Down
41 changes: 39 additions & 2 deletions rpc/jsonrpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ import (

// API version constants
const (
jsonrpcSemverString = "6.2.0"
jsonrpcSemverString = "6.3.0"
jsonrpcSemverMajor = 6
jsonrpcSemverMinor = 2
jsonrpcSemverMinor = 3
jsonrpcSemverPatch = 0
)

Expand Down Expand Up @@ -119,6 +119,7 @@ var handlers = map[string]handler{
"sweepaccount": {fn: (*Server).sweepAccount},
"redeemmultisigout": {fn: (*Server).redeemMultiSigOut},
"redeemmultisigouts": {fn: (*Server).redeemMultiSigOuts},
"removeimported": {fn: (*Server).removeImported},
"stakepooluserinfo": {fn: (*Server).stakePoolUserInfo},
"ticketsforaddress": {fn: (*Server).ticketsForAddress},
"validateaddress": {fn: (*Server).validateAddress},
Expand Down Expand Up @@ -2426,6 +2427,42 @@ func (s *Server) redeemMultiSigOuts(ctx context.Context, icmd interface{}) (inte
return types.RedeemMultiSigOutsResult{Results: rmsoResults}, nil
}

// removeImported purges the provided imported script or private key from the wallet.
func (s *Server) removeImported(ctx context.Context, icmd interface{}) (interface{}, error) {
cmd := icmd.(*types.RemoveImportedCmd)
w, ok := s.walletLoader.LoadedWallet()
if !ok {
return nil, errUnloadedWallet
}

// Parse the imported entity as a private key and remove the associated address.
wif, wErr := dcrutil.DecodeWIF(cmd.Data, w.ChainParams().PrivateKeyID)
if wErr == nil {
serializedPubKey := wif.SerializePubKey()
pubKeyHash := dcrutil.Hash160(serializedPubKey)
addr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash, w.ChainParams(),
dcrec.STEcdsaSecp256k1)
if err != nil {
return nil,
rpcErrorf(dcrjson.ErrRPCInvalidAddressOrKey,
"unable to generate address from pubkey hash: %v", err)
}

err = w.RemoveAddress(addr)
return nil, err
}

// Parse the imported entity as a script and remove the associated address.
addr, err := dcrutil.NewAddressScriptHash([]byte(cmd.Data), w.ChainParams())
if err != nil {
return nil, rpcErrorf(dcrjson.ErrRPCInvalidParameter,
"invalid private key or script provided")
}

err = w.RemoveAddress(addr)
return nil, err
}

// rescanWallet initiates a rescan of the block chain for wallet data, blocking
// until the rescan completes or exits with an error.
func (s *Server) rescanWallet(ctx context.Context, icmd interface{}) (interface{}, error) {
Expand Down
3 changes: 2 additions & 1 deletion rpc/jsonrpc/rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func helpDescsEnUS() map[string]string {
"redeemmultisigout": "redeemmultisigout \"hash\" index tree (\"address\")\n\nTakes the input and constructs a P2PKH paying to the specified address.\n\nArguments:\n1. hash (string, required) Hash of the input transaction\n2. index (numeric, required) Idx of the input transaction\n3. tree (numeric, required) Tree the transaction is on.\n4. address (string, optional) Address to pay to.\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",
"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",
"removeimported": "removeimported \"data\"\n\nRemoves the provided imported script or private key from the wallet.\n\nArguments:\n1. data (string, required) The imported script or private key to remove.\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",
"revoketickets": "revoketickets\n\nRequests the wallet create revovactions for any previously missed tickets. Wallet must be unlocked.\n\nArguments:\nNone\n\nResult:\nNothing\n",
"sendfrom": "sendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\n\nDEPRECATED -- Authors, 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",
Expand Down Expand Up @@ -84,4 +85,4 @@ var localeHelpDescs = map[string]func() map[string]string{
"en_US": helpDescsEnUS,
}

var requestUsages = "abandontransaction \"hash\"\naccountaddressindex \"account\" branch\naccountsyncaddressindex \"account\" branch index\naddmultisigaddress nrequired [\"key\",...] (\"account\")\naddticket \"tickethex\"\nconsolidate inputs (\"account\" \"address\")\ncreatemultisig nrequired [\"key\",...]\ncreatenewaccount \"account\"\ndumpprivkey \"address\"\ngeneratevote \"blockhash\" height \"tickethash\" votebits \"votebitsext\"\ngetaccountaddress \"account\"\ngetaccount \"address\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblockhash\ngetbestblock\ngetblockcount\ngetblockhash index\ngetinfo\ngetmasterpubkey (\"account\")\ngetmultisigoutinfo \"hash\" index\ngetnewaddress (\"account\" \"gappolicy\")\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngetstakeinfo\ngetticketfee\ngettickets includeimmature\ngettransaction \"txid\" (includewatchonly=false)\ngetunconfirmedbalance (\"account\")\ngetvotechoices\ngetwalletfee\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true scanfrom)\nimportscript \"hex\" (rescan=true scanfrom)\nlistaccounts (minconf=1)\nlistaddresstransactions [\"address\",...] (\"account\")\nlistalltransactions (\"account\")\nlistlockunspent\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistscripts\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (\"account\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...])\nlockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\npurchaseticket \"fromaccount\" spendlimit (minconf=1 \"ticketaddress\" numtickets \"pooladdress\" poolfees expiry \"comment\" ticketfee)\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrenameaccount \"oldaccount\" \"newaccount\"\nrescanwallet (beginheight=0)\nrevoketickets\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsendtomultisig \"fromaccount\" amount [\"pubkey\",...] (nrequired=1 minconf=1 \"comment\")\nsetticketfee fee\nsettxfee amount\nsetvotechoice \"agendaid\" \"choiceid\"\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"tree\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nsignrawtransactions [\"rawtx\",...] (send=true)\nstakepooluserinfo \"user\"\nsweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\nticketsforaddress \"address\"\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\nversion\nwalletinfo\nwalletislocked\nwalletlock\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\nwalletpassphrase \"passphrase\" timeout"
var requestUsages = "abandontransaction \"hash\"\naccountaddressindex \"account\" branch\naccountsyncaddressindex \"account\" branch index\naddmultisigaddress nrequired [\"key\",...] (\"account\")\naddticket \"tickethex\"\nconsolidate inputs (\"account\" \"address\")\ncreatemultisig nrequired [\"key\",...]\ncreatenewaccount \"account\"\ndumpprivkey \"address\"\ngeneratevote \"blockhash\" height \"tickethash\" votebits \"votebitsext\"\ngetaccountaddress \"account\"\ngetaccount \"address\"\ngetaddressesbyaccount \"account\"\ngetbalance (\"account\" minconf=1)\ngetbestblockhash\ngetbestblock\ngetblockcount\ngetblockhash index\ngetinfo\ngetmasterpubkey (\"account\")\ngetmultisigoutinfo \"hash\" index\ngetnewaddress (\"account\" \"gappolicy\")\ngetrawchangeaddress (\"account\")\ngetreceivedbyaccount \"account\" (minconf=1)\ngetreceivedbyaddress \"address\" (minconf=1)\ngetstakeinfo\ngetticketfee\ngettickets includeimmature\ngettransaction \"txid\" (includewatchonly=false)\ngetunconfirmedbalance (\"account\")\ngetvotechoices\ngetwalletfee\nhelp (\"command\")\nimportprivkey \"privkey\" (\"label\" rescan=true scanfrom)\nimportscript \"hex\" (rescan=true scanfrom)\nlistaccounts (minconf=1)\nlistaddresstransactions [\"address\",...] (\"account\")\nlistalltransactions (\"account\")\nlistlockunspent\nlistreceivedbyaccount (minconf=1 includeempty=false includewatchonly=false)\nlistreceivedbyaddress (minconf=1 includeempty=false includewatchonly=false)\nlistscripts\nlistsinceblock (\"blockhash\" targetconfirmations=1 includewatchonly=false)\nlisttransactions (\"account\" count=10 from=0 includewatchonly=false)\nlistunspent (minconf=1 maxconf=9999999 [\"address\",...])\nlockunspent unlock [{\"amount\":n.nnn,\"txid\":\"value\",\"vout\":n,\"tree\":n},...]\npurchaseticket \"fromaccount\" spendlimit (minconf=1 \"ticketaddress\" numtickets \"pooladdress\" poolfees expiry \"comment\" ticketfee)\nredeemmultisigout \"hash\" index tree (\"address\")\nredeemmultisigouts \"fromscraddress\" (\"toaddress\" number)\nrenameaccount \"oldaccount\" \"newaccount\"\nremoveimported \"data\"\nrescanwallet (beginheight=0)\nrevoketickets\nsendfrom \"fromaccount\" \"toaddress\" amount (minconf=1 \"comment\" \"commentto\")\nsendmany \"fromaccount\" {\"address\":amount,...} (minconf=1 \"comment\")\nsendtoaddress \"address\" amount (\"comment\" \"commentto\")\nsendtomultisig \"fromaccount\" amount [\"pubkey\",...] (nrequired=1 minconf=1 \"comment\")\nsetticketfee fee\nsettxfee amount\nsetvotechoice \"agendaid\" \"choiceid\"\nsignmessage \"address\" \"message\"\nsignrawtransaction \"rawtx\" ([{\"txid\":\"value\",\"vout\":n,\"tree\":n,\"scriptpubkey\":\"value\",\"redeemscript\":\"value\"},...] [\"privkey\",...] flags=\"ALL\")\nsignrawtransactions [\"rawtx\",...] (send=true)\nstakepooluserinfo \"user\"\nsweepaccount \"sourceaccount\" \"destinationaddress\" (requiredconfirmations feeperkb)\nticketsforaddress \"address\"\nvalidateaddress \"address\"\nverifymessage \"address\" \"signature\" \"message\"\nversion\nwalletinfo\nwalletislocked\nwalletlock\nwalletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\nwalletpassphrase \"passphrase\" timeout"
6 changes: 6 additions & 0 deletions rpc/jsonrpc/types/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,11 @@ func NewRenameAccountCmd(oldAccount, newAccount string) *RenameAccountCmd {
}
}

// RemoveImportedCmd defines the removeimported JSON-RPC command.
type RemoveImportedCmd struct {
Data string
}

// RescanWalletCmd describes the rescanwallet JSON-RPC request and parameters.
type RescanWalletCmd struct {
BeginHeight *int `jsonrpcdefault:"0"`
Expand Down Expand Up @@ -1326,6 +1331,7 @@ func init() {
{"redeemmultisigout", (*RedeemMultiSigOutCmd)(nil)},
{"redeemmultisigouts", (*RedeemMultiSigOutsCmd)(nil)},
{"renameaccount", (*RenameAccountCmd)(nil)},
{"removeimported", (*RemoveImportedCmd)(nil)},
{"rescanwallet", (*RescanWalletCmd)(nil)},
{"revoketickets", (*RevokeTicketsCmd)(nil)},
{"sendfrom", (*SendFromCmd)(nil)},
Expand Down
41 changes: 41 additions & 0 deletions wallet/udb/addressdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package udb
import (
"crypto/sha256"
"encoding/binary"
"fmt"
"time"

"github.com/decred/dcrwallet/errors"
Expand Down Expand Up @@ -796,6 +797,34 @@ func putAddrAccountIndex(ns walletdb.ReadWriteBucket, account uint32, addrHash [
return nil
}

// removeAddrAccountIndex removes the provided key to the address account index of the database.
func removeAddrAccountIndex(ns walletdb.ReadWriteBucket, addrHash []byte) error {
bucket := ns.NestedReadWriteBucket(addrAcctIdxBucketName)
accountB := bucket.Get(addrHash)

if accountB != nil {
msg := fmt.Sprintf("no account value found for address hash %x", addrHash)
return errors.E(errors.IO, msg)
}

err := bucket.Delete(addrHash)
if err != nil {
return errors.E(errors.IO, err)
}

abkt := bucket.NestedReadWriteBucket(accountB)
if err != nil {
return errors.E(errors.IO, err)
}

err = abkt.Delete(addrHash)
if err != nil {
return errors.E(errors.IO, err)
}

return nil
}

// putAccountRow stores the provided account information to the database. This
// is used a common base for storing the various account types.
func putAccountRow(ns walletdb.ReadWriteBucket, account uint32, row *dbAccountRow) error {
Expand Down Expand Up @@ -1093,6 +1122,18 @@ func putAddress(ns walletdb.ReadWriteBucket, addressID []byte, row *dbAddressRow
return putAddrAccountIndex(ns, row.account, addrHash[:])
}

// removeAddress removes the provided address id.
func removeAddress(ns walletdb.ReadWriteBucket, addressID []byte) error {
bucket := ns.NestedReadWriteBucket(addrBucketName)
addrHash := sha256.Sum256(addressID)
err := bucket.Delete(addrHash[:])
if err != nil {
return errors.E(errors.IO, err)
}

return removeAddrAccountIndex(ns, addrHash[:])
}

// putChainedAddress stores the provided chained address information to the
// database.
func putChainedAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32,
Expand Down
5 changes: 5 additions & 0 deletions wallet/udb/addressmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,11 @@ func (m *Manager) ImportScript(ns walletdb.ReadWriteBucket, script []byte) (Mana
return newScriptAddress(m, ImportedAddrAccount, scriptHash)
}

// RemoveAddress removes the provided address from the manager.
func (m *Manager) RemoveAddress(ns walletdb.ReadWriteBucket, addressID []byte) error {
return removeAddress(ns, addressID)
}

// IsLocked returns whether or not the address managed is locked. When it is
// unlocked, the decryption key needed to decrypt private keys used for signing
// is in memory.
Expand Down
Loading

0 comments on commit f10ffde

Please sign in to comment.