Merge pull request #5775 from nuttycom/feature/orchard_list_unspent
Add Orchard support to z_listunspent.
This commit is contained in:
commit
f7b11f6da1
|
@ -5,7 +5,11 @@
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
|
NU5_BRANCH_ID,
|
||||||
assert_equal,
|
assert_equal,
|
||||||
|
get_coinbase_address,
|
||||||
|
nuparams,
|
||||||
|
start_nodes,
|
||||||
wait_and_assert_operationid_status,
|
wait_and_assert_operationid_status,
|
||||||
DEFAULT_FEE
|
DEFAULT_FEE
|
||||||
)
|
)
|
||||||
|
@ -14,9 +18,13 @@ from decimal import Decimal
|
||||||
|
|
||||||
# Test wallet z_listunspent behaviour across network upgrades
|
# Test wallet z_listunspent behaviour across network upgrades
|
||||||
class WalletListNotes(BitcoinTestFramework):
|
class WalletListNotes(BitcoinTestFramework):
|
||||||
|
def setup_nodes(self):
|
||||||
|
return start_nodes(4, self.options.tmpdir, [[
|
||||||
|
nuparams(NU5_BRANCH_ID, 215),
|
||||||
|
]] * 4)
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Current height = 200
|
# Current height = 200 -> Sapling
|
||||||
assert_equal(200, self.nodes[0].getblockcount())
|
assert_equal(200, self.nodes[0].getblockcount())
|
||||||
sproutzaddr = self.nodes[0].z_getnewaddress('sprout')
|
sproutzaddr = self.nodes[0].z_getnewaddress('sprout')
|
||||||
|
|
||||||
|
@ -157,5 +165,52 @@ class WalletListNotes(BitcoinTestFramework):
|
||||||
# TODO: use z_exportviewingkey, z_importviewingkey to test includeWatchonly
|
# TODO: use z_exportviewingkey, z_importviewingkey to test includeWatchonly
|
||||||
# but this requires Sapling support for those RPCs
|
# but this requires Sapling support for those RPCs
|
||||||
|
|
||||||
|
# Set current height to 215 -> NU5
|
||||||
|
self.nodes[0].generate(12)
|
||||||
|
self.sync_all()
|
||||||
|
assert_equal(215, self.nodes[0].getblockcount())
|
||||||
|
|
||||||
|
# Create an Orchard note.
|
||||||
|
account0 = self.nodes[0].z_getnewaccount()['account']
|
||||||
|
ua0 = self.nodes[0].z_getaddressforaccount(account0)['address']
|
||||||
|
receive_amount_4 = Decimal('10.0')
|
||||||
|
recipients = [{"address": ua0, "amount": receive_amount_4}]
|
||||||
|
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
|
||||||
|
txid_4 = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
|
unspent_tx = self.nodes[0].z_listunspent(0)
|
||||||
|
assert_equal(4, len(unspent_tx))
|
||||||
|
# low-to-high in amount
|
||||||
|
unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])
|
||||||
|
|
||||||
|
assert_equal(False, unspent_tx[0]['change'])
|
||||||
|
assert_equal(txid_2, unspent_tx[0]['txid'])
|
||||||
|
assert_equal('sapling', unspent_tx[0]['pool'])
|
||||||
|
assert_equal(True, unspent_tx[0]['spendable'])
|
||||||
|
assert_equal(saplingzaddr, unspent_tx[0]['address'])
|
||||||
|
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
|
||||||
|
|
||||||
|
assert_equal(False, unspent_tx[1]['change'])
|
||||||
|
assert_equal(txid_3, unspent_tx[1]['txid'])
|
||||||
|
assert_equal('sapling', unspent_tx[1]['pool'])
|
||||||
|
assert_equal(True, unspent_tx[1]['spendable'])
|
||||||
|
assert_equal(saplingzaddr2, unspent_tx[1]['address'])
|
||||||
|
assert_equal(receive_amount_3, unspent_tx[1]['amount'])
|
||||||
|
|
||||||
|
assert_equal(True, unspent_tx[2]['change'])
|
||||||
|
assert_equal(txid_3, unspent_tx[2]['txid'])
|
||||||
|
assert_equal('sprout', unspent_tx[2]['pool'])
|
||||||
|
assert_equal(True, unspent_tx[2]['spendable'])
|
||||||
|
assert_equal(sproutzaddr, unspent_tx[2]['address'])
|
||||||
|
assert_equal(change_amount_3, unspent_tx[2]['amount'])
|
||||||
|
|
||||||
|
assert_equal(False, unspent_tx[3]['change'])
|
||||||
|
assert_equal(txid_4, unspent_tx[3]['txid'])
|
||||||
|
assert_equal('orchard', unspent_tx[3]['pool'])
|
||||||
|
assert_equal(True, unspent_tx[3]['spendable'])
|
||||||
|
assert_equal(ua0, unspent_tx[3]['address'])
|
||||||
|
assert_equal(receive_amount_4, unspent_tx[3]['amount'])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
WalletListNotes().main()
|
WalletListNotes().main()
|
||||||
|
|
|
@ -2577,23 +2577,49 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
obj.pushKV("confirmations", entry.confirmations);
|
obj.pushKV("confirmations", entry.confirmations);
|
||||||
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
|
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
|
||||||
obj.pushKV("spendable", hasSaplingSpendingKey);
|
obj.pushKV("spendable", hasSaplingSpendingKey);
|
||||||
obj.pushKV("address", keyIO.EncodePaymentAddress([&]() {
|
auto addr = pwalletMain->GetPaymentAddressForRecipient(entry.op.hash, entry.address);
|
||||||
auto ua = pwalletMain->FindUnifiedAddressByReceiver(entry.address);
|
if (addr.second != RecipientType::WalletInternalAddress) {
|
||||||
if (ua.has_value()) {
|
obj.pushKV("address", keyIO.EncodePaymentAddress(addr.first));
|
||||||
return libzcash::PaymentAddress{ua.value()};
|
}
|
||||||
} else {
|
|
||||||
return libzcash::PaymentAddress{entry.address};
|
|
||||||
}
|
|
||||||
}()));
|
|
||||||
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
|
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
|
||||||
obj.pushKV("memo", HexStr(entry.memo));
|
obj.pushKV("memo", HexStr(entry.memo));
|
||||||
if (hasSaplingSpendingKey) {
|
if (hasSaplingSpendingKey) {
|
||||||
obj.pushKV("change", pwalletMain->IsNoteSaplingChange(saplingNullifiers, entry.address, entry.op));
|
obj.pushKV(
|
||||||
|
"change",
|
||||||
|
pwalletMain->IsInternalRecipient(entry.address) ||
|
||||||
|
pwalletMain->IsNoteSaplingChange(saplingNullifiers, entry.address, entry.op));
|
||||||
}
|
}
|
||||||
results.push_back(obj);
|
results.push_back(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO ORCHARD #5683
|
for (auto & entry : orchardEntries) {
|
||||||
|
UniValue obj(UniValue::VOBJ);
|
||||||
|
obj.pushKV("txid", entry.GetOutPoint().hash.ToString());
|
||||||
|
obj.pushKV("pool", ADDR_TYPE_ORCHARD);
|
||||||
|
obj.pushKV("outindex", (int)entry.GetOutPoint().n);
|
||||||
|
obj.pushKV("confirmations", entry.GetConfirmations());
|
||||||
|
|
||||||
|
// TODO: add a better mechanism for checking whether we have the
|
||||||
|
// spending key for an Orchard receiver.
|
||||||
|
auto ufvkMeta = pwalletMain->GetUFVKMetadataForReceiver(entry.GetAddress());
|
||||||
|
bool haveSpendingKey =
|
||||||
|
ufvkMeta.has_value() &&
|
||||||
|
pwalletMain->GetUnifiedAccountId(ufvkMeta.value().GetUFVKId()).has_value();
|
||||||
|
bool isInternal = pwalletMain->IsInternalRecipient(entry.GetAddress());
|
||||||
|
std::optional<std::string> addrStr;
|
||||||
|
obj.pushKV("spendable", haveSpendingKey);
|
||||||
|
if (!isInternal) {
|
||||||
|
auto ua = pwalletMain->FindUnifiedAddressByReceiver(entry.GetAddress());
|
||||||
|
assert(ua.has_value());
|
||||||
|
obj.pushKV("address", keyIO.EncodePaymentAddress(ua.value()));
|
||||||
|
}
|
||||||
|
obj.pushKV("amount", ValueFromAmount(entry.GetNoteValue()));
|
||||||
|
obj.pushKV("memo", HexStr(entry.GetMemo()));
|
||||||
|
if (haveSpendingKey) {
|
||||||
|
obj.pushKV("change", isInternal);
|
||||||
|
}
|
||||||
|
results.push_back(obj);
|
||||||
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue