Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #2910. Add z_listunspent RPC call. #2913

Merged
merged 1 commit into from
Mar 28, 2018

Conversation

bitcartel
Copy link
Contributor

@bitcartel bitcartel commented Jan 27, 2018

Have tested on network. Opening up for review.

@bitcartel bitcartel added A-wallet Area: Wallet A-rpc-interface Area: RPC interface labels Jan 27, 2018
@bitcartel bitcartel added this to the 1.0.15 milestone Jan 27, 2018
@bitcartel bitcartel self-assigned this Jan 27, 2018
@bitcartel
Copy link
Contributor Author

This PR is helpful in debugging the merging of notes in PR #2797. At the time of writing, you can cherry-pick / rebase ths PR on top of #2797 without any conflict.

Output looks like this:

./zcash-cli z_listunspent
[
  {
    "txid": "abcd...",
    "js_index": 0,
    "output_index": 1,
    "confirmations": 33,
    "address": "zcABCD...",
    "amount": 0.0000xxxx,
    "memo": "beefbeefbeefbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }

@bitcartel bitcartel changed the title Closes #2910. Add z_listunspent RPC call. [WIP] Closes #2910. Add z_listunspent RPC call. Jan 27, 2018
@bitcartel bitcartel changed the title [WIP] Closes #2910. Add z_listunspent RPC call. Closes #2910. Add z_listunspent RPC call. Jan 27, 2018
@bitcartel bitcartel force-pushed the 2910_z_listunspent branch 2 times, most recently from c95d3a0 to bbfa26f Compare January 29, 2018 20:52
@str4d str4d modified the milestones: v1.0.15, v1.1.0 Feb 21, 2018
@bitcartel
Copy link
Contributor Author

bitcartel commented Feb 22, 2018

I'd really like to get this into 1.0.15 (time-permitting) because it complements z_mergetoaddress (for example, a user doesn't know which zaddr has many notes and is a good candidate for consolidation) and users have requested both features. Can you review @arcalinea and @arielg? The PR is pretty much self-contained, adding a new RPC call, and should not change existing behaviour.

Copy link
Contributor

@arcalinea arcalinea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK, pending 1 minor change. I tried the cli interface out and it looks good. Also ran the tests.

// minconf must be >= 0
BOOST_CHECK_THROW(CallRPC("z_listunspent -1"), runtime_error);

// maxconf must be < minconf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxconf must be > minconf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed update to fix this.

@bitcartel bitcartel requested review from braddmiller and removed request for arielgabizon March 14, 2018 18:56
@bitcartel
Copy link
Contributor Author

bitcartel commented Mar 14, 2018

Self-reminder:

  • Check behaviour with viewing keys

@bitcartel
Copy link
Contributor Author

@arcalinea I added support for viewing keys in a second commit which needs review. Thx.

@bitcartel
Copy link
Contributor Author

Added @braddmiller as reviewer, related to locking notes, as we may need a z_listlockunspent RPC call for notes to mirror listlockunspent for utxos.

Copy link
Contributor

@braddmiller braddmiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK. A few non-blocking comments and questions

throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum number of confirmations must be greater or equal to the minimum number of confirmations");
}

std::set<libzcash::PaymentAddress> zaddrs = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already using namespace std, just a non-blocking consistency comment. Future instances of set don't specify the namespace.

BOOST_CHECK_NO_THROW(CallRPC("z_listunspent 1 999 true [\"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP\"]"));

// wrong network, mainnet instead of testnet
BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 true [\"zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U\"]"), runtime_error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear on the purpose of this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just testing that you can't pass in a valid address for a different network. The test case is running on testnet, so we throw it a real mainnet address.

assert(len(results) == 1)
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check assert_equal(results[0]["spendable"], True) here with zero confirmations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've added this, with a comment to clarify the note is unspent (which means its spendable) but it does need 1 confirmation before it can actually be spent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should "spendable" be true if the note has zero confirmations?

Oh, because "spendable" is a misnomer; this field is really designed to distinguish whether the wallet holds a spending key for the address. Let's make sure this is clearly documented in the RPC help.

@arcalinea
Copy link
Contributor

wallet_protectcoinbase.py fails on line 396 wait_and_assert_operationid_status for me, the status is not being returned. Still trying to figure out why...

" \"js_index\" : n (numeric) the joinsplit index\n"
" \"output_index\" : n (numeric) the output index of the joinsplit\n"
" \"confirmations\" : n (numeric) the number of confirmations\n"
" \"spendable\" : true|false (boolean) true if note is spendable, fale if watchonly\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/fale/false/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document that when minconf=0, unspent notes with zero confirmations are included even though they aren't immediately spendable. Or possibly change the field name — either to "have_spending_key", or to "watchonly" reversing the sense.

"\nExamples\n"
+ HelpExampleCli("z_listunspent", "")
+ HelpExampleCli("z_listunspent", "6 9999999 \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
+ HelpExampleRpc("z_listunspent", "6, 9999999 \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above 2 examples are missing a false for watchonly flag:

+ HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
+ HelpExampleRpc("z_listunspent", "6, 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
 

@leto
Copy link
Contributor

leto commented Mar 23, 2018

This has been successfully ported to Hush: MyHush/hush#121 💯

One question I have is about amount=0 notes, which HushList uses. Should they be in the output of z_listunspent ?

I look forward to using z_listunspent and it's improved ease + performance over current methods to get at various data.

@daira
Copy link
Contributor

daira commented Mar 25, 2018

Reviewing now.

Copy link
Contributor

@daira daira left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments.

# This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change.
shieldvalue = Decimal('20.0') - Decimal('0.0001')
recipients = []
recipients.append({"address":myzaddr, "amount": shieldvalue})
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()

# Verify that z_listunspent can return a note which has zero confirmations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"a note that has zero confirmations"

(having zero confirmations is a restrictive qualifier on the note)

assert(len(results) == 1)
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should "spendable" be true if the note has zero confirmations?

Oh, because "spendable" is a misnomer; this field is really designed to distinguish whether the wallet holds a spending key for the address. Let's make sure this is clearly documented in the RPC help.

notes = self.nodes[2].z_listunspent()
sum_of_notes = 0
for note in notes:
sum_of_notes += note["amount"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written as

sum_of_notes = sum([note["amount"] for note in notes])

(also below).

throw runtime_error(
"z_listunspent ( minconf maxconf includeWatchonly [\"zaddr\",...] )\n"
"\nReturns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include notes sent to specified addresses.\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document that addresses may not be duplicated (or remove that restriction).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would make more sense to me to just implicitly deduplicate, unless that's inconsistent with other RPC methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other RPC methods return a duplicated address error message so following that.

" \"js_index\" : n (numeric) the joinsplit index\n"
" \"output_index\" : n (numeric) the output index of the joinsplit\n"
" \"confirmations\" : n (numeric) the number of confirmations\n"
" \"spendable\" : true|false (boolean) true if note is spendable, fale if watchonly\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document that when minconf=0, unspent notes with zero confirmations are included even though they aren't immediately spendable. Or possibly change the field name — either to "have_spending_key", or to "watchonly" reversing the sense.

std::set<PaymentAddress>& filterAddresses,
int minDepth,
int maxDepth,
bool ignoreUnspendable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this parameter to requireSpendingKey or similar.

CWalletTx wtx = p.second;

// Filter the transactions before checking for notes
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth || wtx.GetDepthInMainChain() > maxDepth ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: remove space before closing paren.

}
}
else {
// User did not provide zaddrs, so use default i.e. all addresses
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetUnspentFilteredNotes supports the unfiltered case without having to enumerate all addresses; use that support.

PaymentAddress pa = nd.address;

// skip notes which belong to a different payment address in the wallet
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a questionable API to have the empty set of addresses mean "don't filter by address"; I would expect that not to be treated as a special case and to just return no results. const std::set<PaymentAddress> * with nullptr meaning "don't filter", or boost::optional<const std::set<PaymentAddress>&> (but note portability issues), seem like more appropriate types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach has been used in other related methods; so beyond scope to change in this PR, but have filed ticket: #3118

} catch (const note_decryption_failed &err) {
// Couldn't decrypt with this spending key
throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString()));
} catch (const std::exception &exc) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be narrowed? (I'm concerned about losing stack trace information by rethrowing.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. Won't change for now since its the same for GetFilteredNotes

@daira
Copy link
Contributor

daira commented Mar 25, 2018

@leto wrote:

One question I have is about amount=0 notes, which HushList uses. Should they be in the output of z_listunspent ?

Maybe an optional parameter to filter the minimum value of the notes returned?

@leto
Copy link
Contributor

leto commented Mar 26, 2018

@daira I would definitely find it useful to have an optional parameter that filters out amount=0 notes, which are technically "can be spent" but which most wallet software would like to filter out. In particular, Hush uses many amount=0 notes and this proposed parameter would prevent our frontend from having to process and essentially ignore a lot of data

@bitcartel
Copy link
Contributor Author

Filed #3119 for optional parameter to filter based on note value.

@bitcartel
Copy link
Contributor Author

@daira Force pushed to address review comments. Squashed the two commits into one.

Copy link
Contributor

@daira daira left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@bitcartel bitcartel removed the request for review from str4d March 27, 2018 05:37
@bitcartel
Copy link
Contributor Author

Two ACKs and ported to Hush by @leto (might want to backport some of the latest tweaks and fixed)

@zkbot r+

@zkbot
Copy link
Contributor

zkbot commented Mar 27, 2018

📌 Commit f083d15 has been approved by bitcartel

@zkbot
Copy link
Contributor

zkbot commented Mar 27, 2018

⌛ Testing commit f083d1510f5cf26996e950dcf3bf3cffbabc013d with merge 262ff6c7e8c2afeffcc4e911759b2bbf23062e1f...

@zkbot
Copy link
Contributor

zkbot commented Mar 27, 2018

💔 Test failed - pr-merge

@str4d
Copy link
Contributor

str4d commented Mar 28, 2018

PyFlakes warnings 😄

@bitcartel
Copy link
Contributor Author

Pushed pyflakes fix. @zkbot r+

@zkbot
Copy link
Contributor

zkbot commented Mar 28, 2018

📌 Commit d72c19a has been approved by bitcartel

@zkbot
Copy link
Contributor

zkbot commented Mar 28, 2018

⌛ Testing commit d72c19a with merge 5bdce01...

zkbot added a commit that referenced this pull request Mar 28, 2018
Closes #2910. Add z_listunspent RPC call.

Have tested on network.  Opening up for review.
@zkbot
Copy link
Contributor

zkbot commented Mar 28, 2018

☀️ Test successful - pr-merge
Approved by: bitcartel
Pushing 5bdce01 to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rpc-interface Area: RPC interface A-wallet Area: Wallet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants