Add a finalorchardroot RPC test
This commit is contained in:
parent
b2e4c0562c
commit
4f4ef5537b
|
@ -57,6 +57,7 @@ BASE_SCRIPTS= [
|
|||
'wallet_listreceived.py',
|
||||
'mempool_tx_expiry.py',
|
||||
'finalsaplingroot.py',
|
||||
'finalorchardroot.py',
|
||||
'wallet_orchard.py',
|
||||
'wallet_overwintertx.py',
|
||||
'wallet_persistence.py',
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 The Zcash developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
NU5_BRANCH_ID,
|
||||
assert_equal,
|
||||
connect_nodes_bi,
|
||||
get_coinbase_address,
|
||||
nuparams,
|
||||
start_nodes,
|
||||
wait_and_assert_operationid_status,
|
||||
)
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
SPROUT_TREE_EMPTY_ROOT = "59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7"
|
||||
SAPLING_TREE_EMPTY_ROOT = "3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb"
|
||||
ORCHARD_TREE_EMPTY_ROOT = "2fd8e51a03d9bbe2dd809831b1497aeb68a6e37ddf707ced4aa2d8dff13529ae"
|
||||
NULL_FIELD = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
# Verify block header field 'hashFinalOrchardRoot' (returned in rpc as 'finalorchardroot')
|
||||
# is updated when Orchard transactions with outputs (commitments) are mined into a block.
|
||||
class FinalOrchardRootTest(BitcoinTestFramework):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.num_nodes = 2
|
||||
self.cache_behavior = 'sprout'
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
|
||||
'-txindex', # Avoid JSONRPC error: No information available about transaction
|
||||
'-reindex', # Required due to enabling -txindex
|
||||
nuparams(NU5_BRANCH_ID, 200),
|
||||
'-debug',
|
||||
]] * self.num_nodes)
|
||||
connect_nodes_bi(self.nodes,0,1)
|
||||
self.is_network_split=False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
# Verify genesis block doesn't contain the final orchard root field.
|
||||
blk = self.nodes[0].getblock("0")
|
||||
assert "finalorchardroot" not in blk
|
||||
treestate = self.nodes[0].z_gettreestate("0")
|
||||
assert_equal(treestate["height"], 0)
|
||||
assert_equal(treestate["hash"], self.nodes[0].getblockhash(0))
|
||||
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000")
|
||||
assert "skipHash" not in treestate["sprout"]
|
||||
|
||||
assert_equal(treestate["sapling"]["commitments"]["finalRoot"], NULL_FIELD)
|
||||
# There is no sapling state tree yet, and trying to find it in an earlier
|
||||
# block won't succeed (we're at genesis block), so skipHash is absent.
|
||||
assert "finalState" not in treestate["sapling"]
|
||||
assert "skipHash" not in treestate["sapling"]
|
||||
|
||||
assert_equal(treestate["orchard"]["commitments"]["finalRoot"], NULL_FIELD)
|
||||
# There is no orchard state tree yet, and trying to find it in an earlier
|
||||
# block won't succeed (we're at genesis block), so skipHash is absent.
|
||||
assert "finalState" not in treestate["orchard"]
|
||||
assert "skipHash" not in treestate["orchard"]
|
||||
|
||||
# Verify no generated blocks before NU5 contain the empty root of the Orchard tree.
|
||||
blockcount = self.nodes[0].getblockcount()
|
||||
for height in range(1, blockcount + 1):
|
||||
blk = self.nodes[0].getblock(str(height))
|
||||
assert "finalorchardroot" not in blk
|
||||
|
||||
treestate = self.nodes[0].z_gettreestate(str(height))
|
||||
assert_equal(treestate["height"], height)
|
||||
assert_equal(treestate["hash"], self.nodes[0].getblockhash(height))
|
||||
|
||||
if height < 100:
|
||||
assert "skipHash" not in treestate["sprout"]
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000")
|
||||
|
||||
assert "skipHash" not in treestate["sapling"]
|
||||
assert_equal(treestate["sapling"]["commitments"]["finalRoot"], SAPLING_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["sapling"]["commitments"]["finalState"], "000000")
|
||||
|
||||
assert "skipHash" not in treestate["orchard"]
|
||||
assert_equal(treestate["orchard"]["commitments"]["finalRoot"], NULL_FIELD)
|
||||
assert "finalState" not in treestate["orchard"]
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(11)
|
||||
self.sync_all()
|
||||
|
||||
# post-NU5
|
||||
|
||||
for height in range(200, 211):
|
||||
blk = self.nodes[0].getblock(str(height))
|
||||
assert_equal(blk["finalorchardroot"], ORCHARD_TREE_EMPTY_ROOT)
|
||||
|
||||
treestate = self.nodes[0].z_gettreestate(str(height))
|
||||
assert_equal(treestate["height"], height)
|
||||
assert_equal(treestate["hash"], self.nodes[0].getblockhash(height))
|
||||
|
||||
if height < 100:
|
||||
assert "skipHash" not in treestate["sprout"]
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000")
|
||||
|
||||
assert "skipHash" not in treestate["sapling"]
|
||||
assert_equal(treestate["sapling"]["commitments"]["finalRoot"], SAPLING_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["sapling"]["commitments"]["finalState"], "000000")
|
||||
|
||||
assert "skipHash" not in treestate["orchard"]
|
||||
assert_equal(treestate["orchard"]["commitments"]["finalRoot"], ORCHARD_TREE_EMPTY_ROOT)
|
||||
assert_equal(treestate["orchard"]["commitments"]["finalState"], "000000")
|
||||
|
||||
|
||||
# Node 0 shields some funds
|
||||
taddr0 = get_coinbase_address(self.nodes[0])
|
||||
acct0 = self.nodes[0].z_getnewaccount()['account']
|
||||
addrRes0 = self.nodes[0].z_getaddressforaccount(acct0, ['orchard'])
|
||||
assert_equal(acct0, addrRes0['account'])
|
||||
assert_equal(addrRes0['receiver_types'], ['orchard'])
|
||||
orchardAddr0 = addrRes0['address']
|
||||
recipients = []
|
||||
recipients.append({"address": orchardAddr0, "amount": Decimal('10')})
|
||||
myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0, 'AllowRevealedSenders')
|
||||
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# Verify the final Orchard root has changed
|
||||
blk = self.nodes[0].getblock("211")
|
||||
root = blk["finalorchardroot"]
|
||||
assert root is not ORCHARD_TREE_EMPTY_ROOT
|
||||
assert root is not NULL_FIELD
|
||||
|
||||
# Verify there is a Orchard output description (its commitment was added to tree)
|
||||
result = self.nodes[0].getrawtransaction(mytxid, 1)
|
||||
assert_equal(len(result["orchard"]["actions"]), 2)
|
||||
|
||||
# Since there is a now orchard shielded input in the blockchain,
|
||||
# the orchard values should have changed
|
||||
new_treestate = self.nodes[0].z_gettreestate(str(-1))
|
||||
assert_equal(new_treestate["orchard"]["commitments"]["finalRoot"], root)
|
||||
assert_equal(new_treestate["sprout"], treestate["sprout"])
|
||||
assert new_treestate["orchard"]["commitments"]["finalRoot"] != treestate["orchard"]["commitments"]["finalRoot"]
|
||||
assert new_treestate["orchard"]["commitments"]["finalState"] != treestate["orchard"]["commitments"]["finalState"]
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalRoot"]), 64)
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalState"]), 196)
|
||||
treestate = new_treestate
|
||||
|
||||
# Mine an empty block and verify the final Orchard root does not change
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
assert_equal(root, self.nodes[0].getblock("212")["finalorchardroot"])
|
||||
|
||||
# Mine a block with a transparent tx and verify the final Orchard root does not change
|
||||
taddr1 = self.nodes[1].getnewaddress()
|
||||
self.nodes[0].sendtoaddress(taddr1, Decimal("1.23"))
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(len(self.nodes[0].getblock("213")["tx"]), 2)
|
||||
assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal("1.23"))
|
||||
assert_equal(root, self.nodes[0].getblock("213")["finalorchardroot"])
|
||||
|
||||
# Mine a block with a Sprout shielded tx and verify the final Orchard root does not change
|
||||
zaddr0 = self.nodes[0].listaddresses()[0]['sprout']['addresses'][0]
|
||||
assert_equal(self.nodes[0].z_getbalance(zaddr0), Decimal('50'))
|
||||
recipients = [{"address": taddr0, "amount": Decimal('12.34')}]
|
||||
opid = self.nodes[0].z_sendmany(zaddr0, recipients, 1, 0, 'AllowRevealedRecipients')
|
||||
wait_and_assert_operationid_status(self.nodes[0], opid)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(len(self.nodes[0].getblock("214")["tx"]), 2)
|
||||
assert_equal(self.nodes[0].z_getbalance(zaddr0), Decimal("37.66"))
|
||||
assert_equal(root, self.nodes[0].getblock("214")["finalorchardroot"])
|
||||
|
||||
new_treestate = self.nodes[0].z_gettreestate(str(-1))
|
||||
assert_equal(new_treestate["orchard"]["commitments"]["finalRoot"], root)
|
||||
assert_equal(new_treestate["orchard"], treestate["orchard"])
|
||||
assert new_treestate["sprout"]["commitments"]["finalRoot"] != treestate["sprout"]["commitments"]["finalRoot"]
|
||||
assert new_treestate["sprout"]["commitments"]["finalState"] != treestate["sprout"]["commitments"]["finalState"]
|
||||
assert_equal(len(new_treestate["sprout"]["commitments"]["finalRoot"]), 64)
|
||||
assert_equal(len(new_treestate["sprout"]["commitments"]["finalState"]), 266)
|
||||
treestate = new_treestate
|
||||
|
||||
# Mine a block with a Sapling shielded tx and verify the final Orchard root does not change
|
||||
saplingAddr1 = self.nodes[1].z_getnewaddress("sapling")
|
||||
recipients = [{"address": saplingAddr1, "amount": Decimal('2.34')}]
|
||||
myopid = self.nodes[0].z_sendmany(zaddr0, recipients, 1, 0, 'AllowRevealedAmounts')
|
||||
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(len(self.nodes[0].getblock("215")["tx"]), 2)
|
||||
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal("2.34"))
|
||||
assert_equal(root, self.nodes[0].getblock("215")["finalorchardroot"])
|
||||
|
||||
new_treestate = self.nodes[0].z_gettreestate(str(-1))
|
||||
assert_equal(new_treestate["orchard"]["commitments"]["finalRoot"], root)
|
||||
assert_equal(new_treestate["orchard"], treestate["orchard"])
|
||||
assert new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]
|
||||
assert new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]
|
||||
assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64)
|
||||
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 70)
|
||||
treestate = new_treestate
|
||||
|
||||
# Mine a block with an Orchard shielded recipient and verify the final Orchard root changes
|
||||
acct1 = self.nodes[1].z_getnewaccount()['account']
|
||||
addrRes1 = self.nodes[1].z_getaddressforaccount(acct1, ['orchard'])
|
||||
assert_equal(acct1, addrRes1['account'])
|
||||
assert_equal(addrRes1['receiver_types'], ['orchard'])
|
||||
orchardAddr1 = addrRes1['address']
|
||||
recipients = [{"address": orchardAddr1, "amount": Decimal('2.34')}]
|
||||
myopid = self.nodes[0].z_sendmany(orchardAddr0, recipients, 1, 0)
|
||||
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(len(self.nodes[0].getblock("216")["tx"]), 2)
|
||||
assert_equal(self.nodes[1].z_getbalance(orchardAddr1), Decimal("2.34"))
|
||||
assert root is not self.nodes[0].getblock("216")["finalorchardroot"]
|
||||
|
||||
# Verify there is a Orchard output description (its commitment was added to tree)
|
||||
result = self.nodes[0].getrawtransaction(mytxid, 1)
|
||||
assert_equal(len(result["orchard"]["actions"]), 2) # there is Orchard shielded change
|
||||
|
||||
new_treestate = self.nodes[0].z_gettreestate(str(-1))
|
||||
assert_equal(new_treestate["sprout"], treestate["sprout"])
|
||||
assert_equal(new_treestate["sapling"], treestate["sapling"])
|
||||
assert new_treestate["orchard"]["commitments"]["finalRoot"] != treestate["orchard"]["commitments"]["finalRoot"]
|
||||
assert new_treestate["orchard"]["commitments"]["finalState"] != treestate["orchard"]["commitments"]["finalState"]
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalRoot"]), 64)
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalState"]), 260)
|
||||
treestate = new_treestate
|
||||
|
||||
# Mine a block with an Orchard shielded sender and transparent recipient and verify the final Orchard root changes (because actions)
|
||||
taddr2 = self.nodes[0].getnewaddress()
|
||||
recipients = []
|
||||
recipients.append({"address": taddr2, "amount": Decimal('2.34')})
|
||||
myopid = self.nodes[1].z_sendmany(orchardAddr1, recipients, 1, 0, 'AllowRevealedRecipients')
|
||||
mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid)
|
||||
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(len(self.nodes[0].getblock("217")["tx"]), 2)
|
||||
assert_equal(self.nodes[0].z_getbalance(taddr2), Decimal("2.34"))
|
||||
assert root is not self.nodes[0].getblock("217")["finalorchardroot"]
|
||||
|
||||
# Verify there is a Orchard output description (its commitment was added to tree)
|
||||
result = self.nodes[0].getrawtransaction(mytxid, 1)
|
||||
assert_equal(len(result["orchard"]["actions"]), 2) # there is Orchard shielded change
|
||||
|
||||
new_treestate = self.nodes[0].z_gettreestate(str(-1))
|
||||
assert_equal(new_treestate["sprout"], treestate["sprout"])
|
||||
assert_equal(new_treestate["sapling"], treestate["sapling"])
|
||||
assert new_treestate["orchard"]["commitments"]["finalRoot"] != treestate["orchard"]["commitments"]["finalRoot"]
|
||||
assert new_treestate["orchard"]["commitments"]["finalState"] != treestate["orchard"]["commitments"]["finalState"]
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalRoot"]), 64)
|
||||
assert_equal(len(new_treestate["orchard"]["commitments"]["finalState"]), 260)
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
FinalOrchardRootTest().main()
|
Loading…
Reference in New Issue