Add importmulti RPC call #7551

pull pedrobranco wants to merge 2 commits into bitcoin:master from uphold:feature/rpc-import-multi changing 7 files +797 −0
  1. pedrobranco commented at 5:45 pm on February 17, 2016: contributor

    As discussed in PR #6570 this is a new rpc call importmulti that receives an array of JSON objects representing the intention of importing a public key, a private key, an address and script/p2sh:

     0bitcoin-cli importmulti '[
     1  {
     2    "timestamp": 1455191478,
     3    "type": "privkey",
     4    "value": "<private key>"
     5  },
     6  {
     7    "label": "example 1",
     8    "timestamp": 1455191480,
     9    "type": "pubkey",
    10    "value": "<public key>"
    11  }
    12]' '{"rescan":true}'
    

    and rescans (if not disabled in second argument) the chain from the block that has a timestamp lowest than the lowest timestamp found in all requests, preventing scanning from genesis.

    The output is an array with the status of each request:

    0output: [ { "result": true } , { "result": true } ]
    

    Arguments:

     01. json request array     (json, required) Data to be imported
     1  [
     2    {
     3      "type": "privkey | pubkey | address | script", (string, required) Type of address
     4      "value": "...",                       (string, required) Value of the address
     5      "timestamp": 1454686740,              (integer, optional) Timestamp
     6      "label": "..."                        (string, optional) Label
     7      "p2sh": true | false                  (bool, optional, default=false) Value is a P2SH (type=script only)
     8    }
     9  ,...
    10  ]
    112. json options                 (json, optional) Options
    

    Some notes:

    • If one of the import requests has no timestamp then it should rescan from Genesis (if rescan is not disabled).
    • If all requests fail then it won’t rescan the chain.

    Edit: As suggested by @promag i’ve replaced the second argument (optional) bool to JSON to be easier specify new options and added a new type="script" to support only script values, so can type="address" work only with addresses.

  2. laanwj added the label Wallet on Feb 17, 2016
  3. laanwj commented at 6:22 pm on February 17, 2016: member
    Concept ACK
  4. laanwj added the label Feature on Feb 17, 2016
  5. in src/wallet/rpcdump.cpp: in b974523012 outdated
    616+            } else
    617+                throw;
    618+
    619+            result.pushKV("result", UniValue(true));
    620+            fRunScan = true;
    621+        } catch (...) {
    


    promag commented at 8:24 pm on February 17, 2016:
    @laanwj should we catch specific exceptions to return the error?

    pedrobranco commented at 2:33 pm on February 19, 2016:

    IMO should catch the JSONRPCError and be included on the response, something like:

     0output: [
     1  {
     2    "result": true
     3  },
     4  {
     5    "result": false,
     6    "error": {
     7      "code": -5,
     8      "message": "Invalid Bitcoin address"
     9    }
    10  }
    11]
    

    and catch other exceptions as “missing required fields” (runtime_error). Also maybe changing from “result” to “success”.

  6. in src/wallet/rpcdump.cpp: in b974523012 outdated
    571+        return NullUniValue;
    572+
    573+    if (params.size() == 1)
    574+        RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR));
    575+    else
    576+        RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VBOOL));
    


    promag commented at 8:26 pm on February 17, 2016:
    Only this line is necessary because RPCTypeCheck doesn’t enforce the length. See implementation.

    pedrobranco commented at 10:09 pm on February 17, 2016:
    Will fix.
  7. in src/wallet/rpcdump.cpp: in b974523012 outdated
    538+
    539+UniValue importmulti(const UniValue& params, bool fHelp)
    540+{
    541+    if (fHelp || params.size() < 1 || params.size() > 2)
    542+        throw runtime_error(
    543+            "importmulti '[{\"type\":\"privkey\",\"value\":\"mkjjX...\"},...]' (rescan) \n\n"
    


    promag commented at 10:42 pm on February 17, 2016:
    What about the second argument be a JSON object? Here it would be { "rescan": true }. But it could have more options, for instance, one that would rejects addresses with timestamps belonging to pruned blocks.
  8. in src/wallet/rpcdump.cpp: in b974523012 outdated
    72@@ -72,6 +73,40 @@ std::string DecodeDumpString(const std::string &str) {
    73     return ret.str();
    74 }
    75 
    76+bool ImportPrivateKey(const string& strPrivkey, const string& strLabel)
    


    promag commented at 10:43 pm on February 17, 2016:
    I would move up all auxiliary functions (the ones in title case), then the RPC handlers. WDYT?
  9. instagibbs commented at 2:39 am on February 18, 2016: member

    concept ACK

    I have implemented a method to also simply just import an spv proof + transaction rather than rescan. Would be nice to include that in this as well. (need to add tests and PR…)

  10. pedrobranco force-pushed on Feb 18, 2016
  11. pedrobranco force-pushed on Feb 18, 2016
  12. pedrobranco force-pushed on Feb 18, 2016
  13. jonasschnelli commented at 2:33 pm on February 18, 2016: contributor
    Concept ACK. IIRC, this would be the first RPC command that accept a associative array parameter list (json options (json, optional) Options). IMO this is good but I would prefer a general way of providing key/value parameters for RPC commands (probably out-of-scope for this PR).
  14. in qa/rpc-tests/importmulti.py: in 3f2e87ef7d outdated
     6+from test_framework.test_framework import BitcoinTestFramework
     7+from test_framework.util import *
     8+
     9+class ImportMultiTest (BitcoinTestFramework):
    10+
    11+    def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
    


    instagibbs commented at 8:00 pm on February 18, 2016:
    This is never used?

    pedrobranco commented at 8:05 pm on February 18, 2016:
    True, i will remove.
  15. pedrobranco force-pushed on Feb 19, 2016
  16. laanwj commented at 9:51 am on February 19, 2016: member

    IIRC, this would be the first RPC command that accept a associative array parameter list

    I agree. Though I’ve done a similar thing in #7552. Use positional arguments only for the ’essential’ arguments, and an associative array for everything optional or future-extensible.

    Much less hassle and confusing than APIs with tons of positional arguments, especially optional ones.

  17. promag commented at 10:29 am on February 19, 2016: member
    @jonasschnelli there is also #7518 that accepts options as a JSON object.
  18. luke-jr commented at 11:45 am on February 25, 2016: member
    GBT also uses an options Object
  19. luke-jr referenced this in commit f25959231d on Feb 25, 2016
  20. jtimon commented at 11:10 pm on February 25, 2016: contributor
    concept ACK
  21. pedrobranco force-pushed on Mar 3, 2016
  22. pedrobranco commented at 2:44 pm on March 10, 2016: contributor

    Replaced the output result from [ { “result”: true } , … ] to [ { “success”: true } , … ].

    In case of giving a exception should we show any information of the reason in the result? Something like: [ { “success”: false , error : { “code”: -5, “message”: “Invalid private key encoding” } } , … ]

  23. instagibbs commented at 2:51 pm on March 10, 2016: member
    Passing along error messages would be hugely helpful, yes.
  24. pedrobranco commented at 3:32 pm on March 10, 2016: contributor

    @instagibbs :+1:

    Another thing, currently we match the input to the output status by the order given of the input array. Shouldn’t we put some information of the input (unique enough) in the output to be easier take some action in case of success/failure?

    Example:

    input = [ { type: “address”, value: “myaddress1”}, { type: “address”, value: “myaddress2”}, … ] output = [ { success: true }, { success: true }, … ]

    to something like:

    input = [ { type: “address”, value: “myaddress1”}, { type: “address”, value: “myaddress2”}, … ] output = [ { success: true , reference : { value: “myaddress1”} }, { success: true , reference : { “value”:“myaddress2”} } }, … ]

    Or maybe include in the reference the complete input node . In this case when the user calls the importmulti it can pass any type of extra information that later can be useful to take some action.

  25. instagibbs commented at 3:12 pm on March 14, 2016: member
    I’ll have to defer to others on the value of that. I don’t see much value-add personally but unsure.
  26. pedrobranco force-pushed on Mar 16, 2016
  27. pedrobranco force-pushed on Mar 16, 2016
  28. in qa/rpc-tests/importmulti.py: in 960f08667b outdated
     8+
     9+class ImportMultiTest (BitcoinTestFramework):
    10+    def setup_chain(self):
    11+        print("Initializing test directory "+self.options.tmpdir)
    12+        initialize_chain_clean(self.options.tmpdir, 4)
    13+
    


    mrbandrews commented at 6:55 pm on March 17, 2016:
    Nit: only need to initialize 2 nodes
  29. in qa/rpc-tests/importmulti.py: in 960f08667b outdated
    11+        print("Initializing test directory "+self.options.tmpdir)
    12+        initialize_chain_clean(self.options.tmpdir, 4)
    13+
    14+    def setup_network(self, split=False):
    15+        self.nodes = start_nodes(2, self.options.tmpdir)
    16+        connect_nodes_bi(self.nodes,0,1)
    


    mrbandrews commented at 6:56 pm on March 17, 2016:
    I don’t believe it’s necessary to connect the nodes for this test
  30. in qa/rpc-tests/importmulti.py: in 960f08667b outdated
    13+
    14+    def setup_network(self, split=False):
    15+        self.nodes = start_nodes(2, self.options.tmpdir)
    16+        connect_nodes_bi(self.nodes,0,1)
    17+        self.is_network_split=False
    18+        self.sync_all()
    


    mrbandrews commented at 6:56 pm on March 17, 2016:
    See above, no need to connect/sync
  31. in qa/rpc-tests/importmulti.py: in 960f08667b outdated
    48+
    49+        #Check only one address
    50+        address_info = self.nodes[0].validateaddress(address1)
    51+        assert_equal(address_info['ismine'], True)
    52+
    53+        self.sync_all()
    


    mrbandrews commented at 6:56 pm on March 17, 2016:
    Same comment
  32. mrbandrews commented at 6:59 pm on March 17, 2016: contributor
    Lightly tested ACK. I made a few nit comments on the python test. If you wanted you could add a test that trying to import a private key and scriptpubKey for the same address fails.
  33. pedrobranco force-pushed on Mar 22, 2016
  34. pedrobranco force-pushed on Mar 28, 2016
  35. pedrobranco commented at 1:10 pm on March 28, 2016: contributor
    @mrbandrews Test added.
  36. pedrobranco force-pushed on Mar 28, 2016
  37. in qa/rpc-tests/importmulti.py: in 7fd4248fa3 outdated
    106+        assert_equal(result2[4]['success'], True)
    107+
    108+        # empty json case
    109+        try:
    110+            self.nodes[1].importmulti()
    111+            raise
    


    MarcoFalke commented at 1:31 pm on March 28, 2016:

    Nit: Would be nice to be more verbose here. Maybe move the comment from above into an AssertionError?

    Edit: Also, I don’t like the pass. Effectively the current try-except is a noop. Am I missing something?


    MarcoFalke commented at 2:41 pm on March 28, 2016:

    This is indeed a noop, please remove the code or replace it with something else. Maybe?

     0diff --git a/qa/rpc-tests/importmulti.py b/qa/rpc-tests/importmulti.py
     1index 845bcfe..243e70e 100755
     2--- a/qa/rpc-tests/importmulti.py
     3+++ b/qa/rpc-tests/importmulti.py
     4@@ -108,7 +108,3 @@ class ImportMultiTest (BitcoinTestFramework):
     5         # empty json case
     6-        try:
     7-            self.nodes[1].importmulti()
     8-            raise
     9-        except:
    10-            pass
    11+        assert_raises(JSONRPCException, self.nodes[1].importmulti)
    

    pedrobranco commented at 3:15 pm on March 29, 2016:
    Yes.
  38. in qa/rpc-tests/importmulti.py: in 7fd4248fa3 outdated
    122+        assert_equal(result3[0]['success'], True)
    123+        try:    #JSON field "error" doesn't exist in success:true
    124+            result3[0]['error']
    125+            raise
    126+        except:
    127+            pass
    


    MarcoFalke commented at 2:47 pm on March 28, 2016:
    Nit: Some more dead code
  39. MarcoFalke commented at 2:49 pm on March 28, 2016: member
    Concept ACK
  40. laanwj commented at 9:16 am on March 29, 2016: member
    Needs rebase after #7558
  41. pedrobranco force-pushed on Mar 29, 2016
  42. pedrobranco force-pushed on Mar 29, 2016
  43. pedrobranco commented at 3:30 pm on March 29, 2016: contributor

    Nit: Would be nice to be more verbose here. @MarcoFalke What do you suggest? @laanwj Rebased.

  44. pedrobranco commented at 3:31 pm on April 4, 2016: contributor
    @laanwj Are you considering merging this soon?
  45. pedrobranco force-pushed on Apr 6, 2016
  46. pedrobranco force-pushed on Apr 6, 2016
  47. pedrobranco force-pushed on Apr 6, 2016
  48. sipa commented at 9:40 am on April 14, 2016: member

    Sorry for the very late response here, but I think it’s undesirable to have the “p2sh” flag in this call. The fact that it’s present in importscript is historical, but quite confusing I think (see #7687).

    Here is what happens:

    importaddress “script” p2sh=false

    will mark scriptPubKeys that exactly match script as ismine, but without the ability to spend them, and there is no address added to the wallet (so it will likely be treated as change by the wallet, though show up in listunspent).

    importaddress “script” p2sh=true

    Will do the same as the call above, AND also add script as a known script to the keystore, meaning that it will start treating scriptPubKeys that send to P2SH(script) as ismine too, AND in addition associate the passed label with that P2SH address (but not with the raw script).

    importaddress “address”

    Will mark scriptPubKeys that match the exact script corresponding to address as ismine, AND associate the passed label with it.

    There is a much cleaner distinction here, where importing of scripts and importing of addresses is completely separate. That would mean that where you’d use import script p2sh=true, instead, you’d import both a script and an address.

  49. in src/wallet/rpcdump.cpp: in 90b6183fa8 outdated
    668+            "      \"type\": \"privkey | pubkey | address | script\", (string, required) Type of address\n"
    669+            "      \"value\": \"...\",                                (string, required) Value of the address\n"
    670+            "      \"timestamp\": 1454686740,                         (integer, optional) Timestamp\n"
    671+            "      \"label\": \"...\"                                 (string, optional) Label\n"
    672+            "      \"p2sh\": true | false                             (bool, optional, default=false) Value is a P2SH (type=script only)\n"
    673+            "    }\n"
    


    jonasschnelli commented at 9:54 am on April 14, 2016:

    nit formating:

    0    {
    1      "type": "privkey | pubkey | address | script", (string, required) Type of address
    2      "value": "...",                                (string, required) Value of the address
    3      "timestamp": 1454686740,                         (integer, optional) Timestamp
    4      "label": "..."                                 (string, optional) Label
    5      "p2sh": true | false                             (bool, optional, default=false) Value is a P2SH (type=script only)
    6    }
    
  50. sipa commented at 9:57 am on April 14, 2016: member

    To add some more background: ultimately, there are 3 internal calls that can be issued:

    • AddCScript(redeemscript) allows the wallet to construct scriptSigs for scriptPubKeys that send to P2SH(redeemscript). This only affects ismine when redeemscript itself can be signed for.
    • AddWatchOnly(scriptPubKey) marks a particular scriptPubKey as unconditionally ismine (whether we know how to construct a scriptSig for such an output or not).
    • SetAddressBook(destination) marks outputs set to a scriptPubKey that matches destination as ‘incoming payment’ with a label (rather than our own change). Unfortunately, that does not work for arbitrary scriptPubKeys, only P2SH or P2PKH ones.

    So right now, importaddress “script” p2sh=true calls AddWatchOnly(script), AddCScript(script), SetAddressBook(P2SH(script)). This is a bit inconsistent, as it has effects on outputs. paying to script directly and through P2SH

  51. btcdrak commented at 10:51 am on April 14, 2016: contributor
    concept ACK
  52. pedrobranco commented at 12:26 pm on April 18, 2016: contributor
    @sipa Thanks for the explanation. I’ve added p2sh support only because importaddress rpc call already had it. Do you agree that we should remove p2sh flag from importmulti call?
  53. laanwj commented at 1:30 pm on April 25, 2016: member

    Maybe I’m misunderstanding this, but I think the type should fully specify what kind of object is imported:

    0      "type": "privkey | pubkey | address | script", (string, required) Type of address
    

    This makes an extra P2SH flag redundant.

  54. sipa commented at 1:33 pm on April 25, 2016: member
    script is ambiguous: it can mean “i’m importing this script, so that when it is used as a P2SH redeemscript, the client knows how to sign it”, or “i want outputs spending to this exact script to be counting towards my balance and listunspent”.
  55. laanwj commented at 1:34 pm on April 25, 2016: member
    Then add a different type for either case?
  56. laanwj commented at 1:36 pm on April 25, 2016: member
    eh, the “i’m importing this script, so that when it is used as a P2SH redeemscript, the client knows how to sign it” case probably doesn’t belong here at all, as it relates to signing and doesn’t affect the balance/rescan?
  57. sipa commented at 1:38 pm on April 25, 2016: member
    @laanwj It does, because if that script itself uses keys that are known to the wallet, it will make such outputs be considered spendable.
  58. sipa commented at 3:32 pm on April 25, 2016: member

    I’m sorry for just mentioning some background and complaints, and not offering a good solution. But I think we have a mess that is caused by having half a dozen different ways through which a script can be considered spendable/solvable/ismine, and having magic import commands with many edge cases (like importaddress now) that just try to do as much as possible, and we should not maintain that in newer APIs.

    One solution is to break it down to the lowest-level CKeyStore changes, and providing a means to individually add:

    • privkey (which helps spendability, causing outputs always to be treated as ismine)
    • pubkeys/redeemscripts (which helps solvability, and if that indirectly leads to a spendable script, it causes outputs to be treated as ismine)
    • watched scripts (which always causes outputs to be treated as ismine, regardless of spendability)
    • labels (which makes the wallet treat such transactions as incoming funds, which is only possible for scripts that map to a CTxDestination)

    However, it would be highly inconvenient to use (you’d sometimes need 3 separate entries to get the behaviour of a single call now).

    Here is a proposal, but it’s quite a bit different from the existing design: the input is a list of Objects, each of which has the following keys:

    • output mandatory string an address or a hex-encoded script, describing exactly what outputs we’re talking about, this is mandatory
    • redeemscript optional string and only allowed if the address is a P2SH address or a P2SH scriptPubKey, and it must correspond to that output.
    • pubkeys optional array of strings giving pubkeys that must occur in the output or redeemscript
    • keys: optional array of strings, giving private keys whose corresponding public keys must occur in the output or redeemscript
    • internal optional bool (default false) stating whether matching outputs should be be treated as not incoming payments. Must be explicitly set to false for outputs that don’t have a corresponding CTxDestination (so a warning/error can be given)
    • watchonly optional bool (default false) stating whether matching outputs should be considered watched even when they’re not spendable. If this is not given, importing this entry must result in the specified outputs becoming spendable.
    • label optional string (default "" if internal=false, none if internal=true) to assign to the address (aka account name, for now), only allowed with internal=false
    • timestamp as now (though perhaps we should consider that the timestamp for an individual key should be stored in mapKeyMetaData, and not just in nTimeFirstKey.

    This is a bit redundant and less convenient (it always requires specifying a script or address, and either keys), but I think it allows for very accurate error messages whenever the behaviour wouldn’t match the user’s expectations. It also makes it obvious where the current codebase’s restrictions are (you can’t make a non-standard scriptPubKey non-internal, only individual keys can be assigned a birth time, …), which can be loosened in future iterations if those restrictions are solved.

    Open for discussion of course!

  59. promag commented at 1:41 pm on May 2, 2016: member

    @sipa thanks for these insights!

    Totally agree with @sipa regarding the object keys. Specially because there is no type key 👏 With these keys we can be sure the caller knows his business.

  60. promag commented at 1:47 pm on May 2, 2016: member
    @sipa replace output by scriptPubKey ?
  61. sipa commented at 1:52 pm on May 2, 2016: member

    @promag I considered that, but if it’s an address, it’s not really a scriptPubKey (especially if there is ever support for things like stealth addresses (which contain cryptographic information that never actually directly ends up in the scriptPubKey).

    Perhaps there should be two separate fields, address or scriptPubKey, and you’re required to exactly provide one of them.

  62. pedrobranco commented at 2:59 pm on May 2, 2016: contributor

    @sipa ACK and thanks for the proposal.

    Also, when calling with the private keys and watchonly=true. Should we throw an error / warn the user that he should use pubkeys instead if he wants watch-only? Or should we allow importing private keys in watch-only (deriving the pubkey)?

  63. in qa/rpc-tests/importmulti.py: in 90b6183fa8 outdated
    0@@ -0,0 +1,147 @@
    1+#!/usr/bin/env python2
    


    MarcoFalke commented at 9:37 am on May 6, 2016:
    Mind to change this to py3?

    pedrobranco commented at 10:04 am on May 6, 2016:
    Sure.
  64. promag commented at 9:27 am on May 25, 2016: member

    @promag I considered that, but if it’s an address, it’s not really a scriptPubKey (especially if there is ever support for things like stealth addresses (which contain cryptographic information that never actually directly ends up in the scriptPubKey). @sipa maybe we could go with:

    • { "scriptPubKey": <script> }
    • { "scriptPubKey": { "address": <address> } }

    It’s scalable and unambiguous. WDYT?

  65. promag commented at 9:28 am on May 25, 2016: member
    @arowser this is still work in progress.
  66. sipa commented at 1:57 pm on May 25, 2016: member
    @promag Looks good to me.
  67. laanwj added this to the milestone 0.13.0 on Jun 8, 2016
  68. laanwj commented at 12:04 pm on June 8, 2016: member

    As this is very often requested functionality I’d really like to get this in for 0.13.

    Note that the deadline for features for 0.13 is June 16, so that would mean we’ll have to get it to a mergeable state in a week. Is that realistic?

  69. pedrobranco commented at 1:54 pm on June 8, 2016: contributor
    @laanwj Yes, i think is realistic.
  70. laanwj commented at 9:24 am on June 13, 2016: member
    Ping…
  71. pedrobranco commented at 11:43 am on June 13, 2016: contributor
    @laanwj I’m working on this with @promag and we’ll try to push a solution as fastest as we can (probably by tomorrow).
  72. pedrobranco commented at 10:21 am on June 15, 2016: contributor

    @laanwj We have a partial solution but is not complete:

    • Does not checks the consistency between private/pub keys and scriptPubKey / redeemScript.
    • Does not support internal and watchonly modes.

    We’ve made a major refactor and unfortunately we think we are late for the 0.13 milestone.

  73. pedrobranco force-pushed on Jun 15, 2016
  74. in qa/rpc-tests/importmulti.py: in 8255b35f6c outdated
     7+from test_framework.util import *
     8+
     9+class ImportMultiTest (BitcoinTestFramework):
    10+    def setup_chain(self):
    11+        print("Initializing test directory "+self.options.tmpdir)
    12+        initialize_chain_clean(self.options.tmpdir, 2)
    


    MarcoFalke commented at 7:41 pm on June 15, 2016:

    Could you use __init__ for that, instead of overwriting setup_chain?

    I.e. something like

    0    def __init__(self):
    1        super().__init__()
    2        self.num_nodes = 2
    3        self.setup_clean_chain = True
    

    pedrobranco commented at 9:28 am on June 16, 2016:
    Sure, and looks way better.
  75. in qa/pull-tester/rpc-tests.py: in 8255b35f6c outdated
    136@@ -137,6 +137,7 @@
    137     'p2p-versionbits-warning.py',
    138     'importprunedfunds.py',
    139     'signmessages.py',
    140+    'importmulti.py'
    


    MarcoFalke commented at 9:32 am on June 16, 2016:
    micro-Nit: missing trailing ,
  76. in qa/rpc-tests/importmulti.py: in 8255b35f6c outdated
    14+    def setup_network(self, split=False):
    15+        self.nodes = start_nodes(2, self.options.tmpdir)
    16+        self.is_network_split=False
    17+
    18+    def run_test (self):
    19+        import time
    


    MarcoFalke commented at 9:33 am on June 16, 2016:
    Nit: Might as well place this in the header
  77. pedrobranco force-pushed on Jun 16, 2016
  78. pedrobranco force-pushed on Jun 16, 2016
  79. laanwj commented at 1:51 pm on June 20, 2016: member

    Looks good to me - utACK https://github.com/bitcoin/bitcoin/pull/7551/commits/d72a88616f3ad0578ca6e6d8f025db5574f9bf07

    Does not support internal and watchonly modes.

    Seems acceptable for a first version, it’s not documented either so that’s consistent.

    We’ve made a major refactor and unfortunately we think we are late for the 0.13 milestone.

    I’m afraid so too, if we would merge it now it would be very last-minute, I don’t think this code is well-tested enough. Code does get more testing on master, but so close to a release it’s more risky, we don’t want to release with something broken.

  80. pedrobranco commented at 2:29 pm on June 20, 2016: contributor

    Code does get more testing on master, but so close to a release it’s more risky, we don’t want to release with something broken.

    I totally agree.

    Still we need help on how to implement internal mode and watch-only, and the consistency checking (technical doubts, so we’ll need to do some researching).

  81. sipa commented at 2:31 pm on June 20, 2016: member
    I promise to help with this (nag me if I forget), but after 0.13 is branched off.
  82. pedrobranco commented at 2:56 pm on June 20, 2016: contributor

    I promise to help with this (nag me if I forget), but after 0.13 is branched off.

    Thanks for the support.

    I have some doubts about the expected result in some situations:

    • When we have private keys on keys and watch-only=true what should we do:
      • import the public key of each given key?
      • import the private key and mark it somehow to unspentable / watchable only?
    • The watch-only concept should not import and save any private key, @sipa agree?

    About the internal concept I’m a bit confused on how it should work.

  83. laanwj commented at 8:32 am on June 21, 2016: member
    @pedrobranco Removing the 0.13 milestone then - thanks for your patience!
  84. MarcoFalke removed this from the milestone 0.13.0 on Jun 21, 2016
  85. luke-jr referenced this in commit ac96079d55 on Jun 28, 2016
  86. luke-jr referenced this in commit e69c0b5be2 on Jun 28, 2016
  87. sipa commented at 10:04 am on July 1, 2016: member

    I think if private keys are given and watchonly, you should fail. The reason for the watchonly option is to indicate that you intentionally are not providing a private key, and are not expecting the ability to spend. It’s there so that if someone just forgets to provide a private key (as opposed to making it intentionally watch-only), the call can warn them by failing.

    The internal concept is similar to watchonly. When it is present, you’re not adding the address to the addressbook (so no label, not even an empty label). This makes it incompatible with the label option. But also for example, when the scriptPubKey is given in hex form and not in a standard type that can be internally converted to a CTxDestination, internal must be set, as there would be no way to add it to the address book (at this point).

  88. pedrobranco commented at 10:11 am on July 1, 2016: contributor
    @sipa ACK.
  89. pedrobranco force-pushed on Jul 1, 2016
  90. pedrobranco force-pushed on Jul 18, 2016
  91. pedrobranco commented at 5:12 pm on July 18, 2016: contributor
    Consistency check added + internal + watchonly.
  92. pedrobranco commented at 9:31 am on July 28, 2016: contributor
    Can someone please review the PR?
  93. jonasschnelli commented at 9:32 am on July 28, 2016: contributor
    Will test today.
  94. in src/chain.cpp: in 7832208760 outdated
    69+    }
    70+};
    71+
    72+CBlockIndex* CChain::FindLatestBefore(int64_t nTime) const
    73+{
    74+    std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime, SmallerThanTimestamp());
    


    jonasschnelli commented at 10:03 am on July 28, 2016:

    Using c++11 lambda here?

    Something like:

    0std::lower_bound(vChain.begin(), vChain.end(), nTime,
    1   [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTime() < time; }
    2);
    

    Would probably be less confusing to read.

  95. in src/wallet/rpcdump.cpp: in 7832208760 outdated
    988+        const UniValue result = processImport(data);
    989+        response.push_back(result);
    990+    }
    991+
    992+    if (fRescan && fRunScan && request.size()) {
    993+        CBlockIndex* pindex = nLowestTimestamp > 0 ? chainActive.FindLatestBefore(nLowestTimestamp) : chainActive.Genesis();
    


    jonasschnelli commented at 10:10 am on July 28, 2016:

    Are you sure this is correct? I can’t see a link between the input timestamp and nLowestTimestamp. In case of a rescan, nLowestTimestamp is always chainActive.Tip()->GetBlockTime() which is incorrect IMO.

    Also, we should add a time- or block-delta between nLowestTimestamp and the actual rescan height. Timestamps could be slightly wrong (timezones, failed implementations, accuracy). Maybe we should go down another 144 blocks.


    pedrobranco commented at 11:03 am on July 29, 2016:

    It was left out in this latest proposal, so I will fix that.

    Maybe we should go down another 144 blocks.

    I’m not quite sure about rescanning in a different timestamp that the user specifies, given that he knows what’s he doing. Is there any reason for the 144 blocks?


    jonasschnelli commented at 11:50 am on July 29, 2016:
    144 blocks = 1day. I think going back/deeper one day is reasonable.
  96. in src/wallet/rpcdump.cpp: in 7832208760 outdated
    983+        fRescan = false;
    984+
    985+    UniValue response(UniValue::VARR);
    986+
    987+    BOOST_FOREACH (const UniValue& data, request.getValues()) {
    988+        const UniValue result = processImport(data);
    


    jonasschnelli commented at 10:25 am on July 28, 2016:
    To bad we need to hold cs_main for this. But I think its not possible without it with the current lock structure.
  97. in src/wallet/rpcdump.cpp: in 7832208760 outdated
    750+                    pwalletMain->MarkDirty();
    751+                    pwalletMain->SetAddressBook(vchAddress, label, "receive");
    752+
    753+                    if (pwalletMain->HaveKey(vchAddress))
    754+                        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
    755+                    ;
    


    jonasschnelli commented at 10:27 am on July 28, 2016:
    nit: ; can be removed; mini-nit: You are using “ifs without brackets” together with some “ifs with brackets”.
  98. in src/wallet/rpcdump.cpp: in 7832208760 outdated
    972+    }
    973+
    974+    LOCK2(cs_main, pwalletMain->cs_wallet);
    975+    EnsureWalletIsUnlocked();
    976+
    977+    bool fRunScan = false;
    


    jonasschnelli commented at 6:21 pm on July 28, 2016:
    fRunScan is always false which result in never triggering a rescan.

    pedrobranco commented at 10:47 am on July 29, 2016:
    I will check if any of the requests returns success=true, then allow the rescan (fRunScan = true) if not disabled via options.

    jonasschnelli commented at 11:49 am on July 29, 2016:

    I think that is not correct. There are two appearance of the variable fRunScan, one on L977 (bool fRunScan = false;) and one on L992 (if (fRescan && fRunScan && request.size()) {).

    I can’t see a code part where fRunScan will be set to true.


    pedrobranco commented at 1:15 pm on July 29, 2016:

    What I have meant in the comment is that after pushing the fix it it will do what I’ve described:

    I will check if any of the requests returns success=true, then allow the rescan (fRunScan = true) if not disabled via options.

  99. jonasschnelli commented at 6:22 pm on July 28, 2016: contributor
    The rescan behavior seems not to work, I’m happy to test again once this is fixed. We really want to have importmulti in 0.14.
  100. jonasschnelli added this to the milestone 0.14 on Jul 28, 2016
  101. pedrobranco force-pushed on Jul 29, 2016
  102. pedrobranco force-pushed on Aug 2, 2016
  103. pedrobranco commented at 9:31 am on August 3, 2016: contributor
    @jonasschnelli Can you please test the rescan behavior?
  104. in src/wallet/rpcdump.cpp: in 51fd0d6a61 outdated
    1054+            nLowestTimestamp = timestamp;
    1055+        }
    1056+    }
    1057+
    1058+    if (fRescan && fRunScan && request.size()) {
    1059+        CBlockIndex* pindex = nLowestTimestamp > 0 ? chainActive.FindLatestBefore(nLowestTimestamp) : chainActive.Genesis();
    


    jonasschnelli commented at 3:34 pm on August 4, 2016:
    I guess nLowestTimestamp is always > 0.
  105. pedrobranco force-pushed on Aug 4, 2016
  106. luke-jr referenced this in commit b48d08b325 on Aug 7, 2016
  107. luke-jr referenced this in commit 81a7fab0cb on Aug 9, 2016
  108. laanwj commented at 10:17 am on September 9, 2016: member
    What needs to be done here?
  109. pedrobranco commented at 11:03 am on September 9, 2016: contributor

    What needs to be done here?

    Maybe add some tests for the rescan feature.

  110. laanwj commented at 2:03 pm on September 19, 2016: member
    Personally, I don’t know the opinion of others, I’d really like to move forward and merge this if the base functionality is agreed on. There is still enough time before 0.14 to fix problems, add tests, add features etc.
  111. in src/wallet/rpcdump.cpp: in 1bcc021f7c outdated
    1026+    bool fRunScan = false;
    1027+    const int64_t minimumTimestamp = 1;
    1028+    int64_t nLowestTimestamp;
    1029+
    1030+    if (fRescan && chainActive.Tip()) {
    1031+        nLowestTimestamp = chainActive.Tip()->GetBlockTime();
    


    jonasschnelli commented at 2:28 pm on September 28, 2016:
    nit: using chainActive.Tip()s blocktime with the later FindLatestBefore(nLowestTimestamp) will probably always result in re-scaning a couple 1-2 blocks when importing with a timestamp in future.

    pedrobranco commented at 2:54 pm on September 28, 2016:

    We can prevent rescanning if nLowestTimestamp is in the future:

    0if (fRescan && fRunScan && request.size() && nLowestTimestamp <= chainActive.Tip()->GetBlockTime()) {
    1(...)
    
  112. in src/wallet/rpcdump.cpp: in 1bcc021f7c outdated
    1029+
    1030+    if (fRescan && chainActive.Tip()) {
    1031+        nLowestTimestamp = chainActive.Tip()->GetBlockTime();
    1032+    } else {
    1033+        fRescan = false;
    1034+    }
    


    jonasschnelli commented at 2:32 pm on September 28, 2016:
    This else should be removed because it can only set a already false fRescan again to false.

    pedrobranco commented at 2:44 pm on September 28, 2016:
    fRescan is initially set to true.

    jonasschnelli commented at 2:46 pm on September 28, 2016:
    Argh. Your right. Got fooled by fRunScan, fRescan. Nevermind then.

    pedrobranco commented at 2:57 pm on September 28, 2016:
    No problem @jonasschnelli .
  113. jonasschnelli approved
  114. jonasschnelli commented at 2:43 pm on September 28, 2016: contributor
    Tested ACK 1bcc021f7c27d605dbecebdcb40e0657a1501be2 (trivial rebase issue [only rpc-tests.py] can be done during merging), nits can be addresses after merging.
  115. pedrobranco force-pushed on Sep 28, 2016
  116. pedrobranco commented at 9:21 am on September 29, 2016: contributor
    Rebased and nits addressed.
  117. in src/wallet/rpcdump.cpp: in e4d03e7ab0 outdated
    840+                // add to address book or update label
    841+                if (pubKeyAddress.IsValid()) {
    842+                    pwalletMain->SetAddressBook(pubKeyAddress.Get(), label, "receive");
    843+                }
    844+
    845+                // TODO Is this necessary?
    


    laanwj commented at 2:46 pm on October 5, 2016:
    It looks like you’re doing the IsMine/HaveWatchOnly/AddWatchOnly dance twice here. Why?

    pedrobranco commented at 9:47 am on October 6, 2016:

    I was wondering the same when I checked the RPC call importpubkey, which calls the same dance in here.

    In doubt, and since I did want to change the behavior of importing pub keys, I’ve added the TODO mark for revision of this part of the code.

  118. laanwj commented at 1:33 pm on October 19, 2016: member
    Needs (easy) rebase in rpcwallet.cpp after #8788
  119. Add importmulti rpc call cb08fdbf78
  120. Add consistency check to RPC call importmulti 215caba4ed
  121. pedrobranco force-pushed on Oct 19, 2016
  122. pedrobranco commented at 9:44 pm on October 19, 2016: contributor
    Rebased.
  123. jonasschnelli commented at 6:57 am on October 20, 2016: contributor
    Re-Tested ACK 215caba4ed4547d6f2a0954fa9fe1ae78f4a7c40 I think this is ready for merge. Possible optimizations and nit-fixing can be done separately.
  124. laanwj merged this on Oct 20, 2016
  125. laanwj closed this on Oct 20, 2016

  126. laanwj referenced this in commit f2d705629b on Oct 20, 2016
  127. laanwj commented at 7:05 am on October 20, 2016: member

    I think this is ready for merge. Possible optimizations and nit-fixing can be done separately.

    Yes, agreed. The code is self-contained so the risk of regressions is minimal. The importmulti RPC call should be considered experimental for now, but 0.14 is still a few months away anyhow.

  128. luke-jr referenced this in commit eb039ce0c5 on Oct 20, 2016
  129. luke-jr referenced this in commit 12e852a616 on Oct 20, 2016
  130. rebroad commented at 2:31 am on October 25, 2016: contributor

    bisect identifies cb08fdbf78685b55029768524ca867772711c32b as the commit that causes the compile to fail with:-

     0make src/qt/bitcoin-qt
     1Makefile:1169: warning: overriding commands for target `src/qt/bitcoin-qt'
     2Makefile:1107: warning: ignoring old commands for target `src/qt/bitcoin-qt'
     3make -C src qt/bitcoin-qt
     4make[1]: Entering directory `/home/rebroad/src/bitcoin/src'
     5  CXX      wallet/libbitcoin_wallet_a-rpcdump.o
     6wallet/rpcdump.cpp: In function UniValue processImport(const UniValue&):
     7wallet/rpcdump.cpp:869:37: error: pubkey was not declared in this scope
     8                 CKeyID vchAddress = pubkey.GetID();
     9                                     ^
    10make[1]: *** [wallet/libbitcoin_wallet_a-rpcdump.o] Error 1
    11make[1]: Leaving directory `/home/rebroad/src/bitcoin/src'
    12make: *** [src/qt/bitcoin-qt] Error 2
    

    I am confused as to how this tested ok and got merged when it doesn’t compile..

  131. in src/wallet/rpcdump.cpp: in 215caba4ed
    766+                    }
    767+
    768+                    CPubKey pubkey = key.GetPubKey();
    769+                    assert(key.VerifyPubKey(pubkey));
    770+
    771+                    CKeyID vchAddress = pubkey.GetID();
    


    rebroad commented at 2:53 am on October 25, 2016:
    pubKey is not defined…. pubkey is though!
  132. laanwj commented at 5:34 am on October 25, 2016: member

    This has not given any compile issues for anyone else besides a boost issue which was fixed later ( #8980). Also when I look at the source, pubkey is simply defined as:

    0CPubKey pubkey = key.GetPubKey();
    

    If you are trying to merge this into some other code base do not complain here if the build breaks.

  133. codablock referenced this in commit 0de540fd3e on Sep 19, 2017
  134. codablock referenced this in commit efded3ca9c on Jan 13, 2018
  135. andvgal referenced this in commit c282ca9ead on Jan 6, 2019
  136. CryptoCentric referenced this in commit f550288a38 on Feb 15, 2019
  137. str4d referenced this in commit 33293c7586 on Dec 6, 2019
  138. str4d referenced this in commit 6e8f11cde0 on Dec 9, 2019
  139. str4d referenced this in commit df00e51e3e on Dec 19, 2019
  140. zkbot referenced this in commit 900ed4555f on Dec 19, 2019
  141. furszy referenced this in commit a279df6e61 on Apr 6, 2021
  142. DrahtBot locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-08 19:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me