Merge pull request #5560 from steven-ecc/z_gettreestate_update_for_orchard

Add Orchard support to the z_gettreestate RPC
This commit is contained in:
str4d 2022-02-18 03:17:05 +00:00 committed by GitHub
commit 6cd5b8792b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 19 deletions

View File

@ -6,9 +6,11 @@
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,
)
@ -17,6 +19,7 @@ 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 'hashFinalSaplingRoot' (returned in rpc as 'finalsaplingroot')
@ -25,17 +28,16 @@ class FinalSaplingRootTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.num_nodes = 2
self.setup_clean_chain = True
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
'-txindex', # Avoid JSONRPC error: No information available about transaction
nuparams(NU5_BRANCH_ID, 210),
'-debug',
]] * self.num_nodes)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
connect_nodes_bi(self.nodes,0,3)
self.is_network_split=False
self.sync_all()
@ -52,13 +54,19 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT)
assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000")
assert("skipHash" not in treestate["sprout"])
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 "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 all generated blocks contain the empty root of the Sapling tree.
blockcount = self.nodes[0].getblockcount()
@ -70,14 +78,18 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert_equal(treestate["height"], height)
assert_equal(treestate["hash"], self.nodes[0].getblockhash(height))
assert("skipHash" not in treestate["sprout"])
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 "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)
# Node 0 shields some funds
taddr0 = get_coinbase_address(self.nodes[0])
saplingAddr0 = self.nodes[0].z_getnewaddress('sapling')
@ -93,8 +105,8 @@ class FinalSaplingRootTest(BitcoinTestFramework):
# Verify the final Sapling root has changed
blk = self.nodes[0].getblock("201")
root = blk["finalsaplingroot"]
assert(root is not SAPLING_TREE_EMPTY_ROOT)
assert(root is not NULL_FIELD)
assert root is not SAPLING_TREE_EMPTY_ROOT
assert root is not NULL_FIELD
# Verify there is a Sapling output description (its commitment was added to tree)
result = self.nodes[0].getrawtransaction(mytxid, 1)
@ -105,8 +117,8 @@ class FinalSaplingRootTest(BitcoinTestFramework):
new_treestate = self.nodes[0].z_gettreestate(str(-1))
assert_equal(new_treestate["sapling"]["commitments"]["finalRoot"], root)
assert_equal(new_treestate["sprout"], treestate["sprout"])
assert(new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"])
assert(new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"])
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
@ -145,8 +157,8 @@ class FinalSaplingRootTest(BitcoinTestFramework):
new_treestate = self.nodes[0].z_gettreestate(str(-1))
assert_equal(new_treestate["sapling"]["commitments"]["finalRoot"], root)
assert_equal(new_treestate["sapling"], treestate["sapling"])
assert(new_treestate["sprout"]["commitments"]["finalRoot"] != treestate["sprout"]["commitments"]["finalRoot"])
assert(new_treestate["sprout"]["commitments"]["finalState"] != treestate["sprout"]["commitments"]["finalState"])
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"]), 134)
treestate = new_treestate
@ -164,7 +176,7 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getblock("205")["tx"]), 2)
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal("12.34"))
assert(root is not self.nodes[0].getblock("205")["finalsaplingroot"])
assert root is not self.nodes[0].getblock("205")["finalsaplingroot"]
# Verify there is a Sapling output description (its commitment was added to tree)
result = self.nodes[0].getrawtransaction(mytxid, 1)
@ -172,8 +184,8 @@ class FinalSaplingRootTest(BitcoinTestFramework):
new_treestate = self.nodes[0].z_gettreestate(str(-1))
assert_equal(new_treestate["sprout"], treestate["sprout"])
assert(new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"])
assert(new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"])
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"]), 136)
treestate = new_treestate
@ -200,6 +212,21 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert_equal(new_treestate["sprout"], treestate["sprout"])
assert_equal(new_treestate["sapling"], treestate["sapling"])
# Activate NU5; more testing should be added once we can mine orchard transactions.
self.sync_all()
self.nodes[0].generate(4)
self.sync_all()
new_treestate = self.nodes[0].z_gettreestate(str(-1))
# sprout and sapling results should not change
assert_equal(new_treestate["sprout"], treestate["sprout"])
assert_equal(new_treestate["sapling"], treestate["sapling"])
assert "skipHash" not in treestate["orchard"]
assert_equal(new_treestate["orchard"]["commitments"]["finalRoot"], ORCHARD_TREE_EMPTY_ROOT)
assert_equal(new_treestate["orchard"]["commitments"]["finalState"], "00")
pass
if __name__ == '__main__':
FinalSaplingRootTest().main()

View File

@ -1247,6 +1247,13 @@ UniValue z_gettreestate(const UniValue& params, bool fHelp)
" \"finalRoot\": \"hex\", (string)\n"
" \"finalState\": \"hex\" (string)\n"
" }\n"
" },\n"
" \"orchard\": {\n"
" \"skipHash\": \"hash\", (string) hash of most recent block with more information\n"
" \"commitments\": {\n"
" \"finalRoot\": \"hex\", (string)\n"
" \"finalState\": \"hex\" (string)\n"
" }\n"
" }\n"
"}\n"
"\nExamples:\n"
@ -1327,6 +1334,31 @@ UniValue z_gettreestate(const UniValue& params, bool fHelp)
res.pushKV("sapling", sapling_result);
}
// orchard
{
UniValue orchard_result(UniValue::VOBJ);
UniValue orchard_commitments(UniValue::VOBJ);
orchard_commitments.pushKV("finalRoot", pindex->hashFinalOrchardRoot.GetHex());
bool need_skiphash = false;
OrchardMerkleFrontier tree;
if (pcoinsTip->GetOrchardAnchorAt(pindex->hashFinalOrchardRoot, tree)) {
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
s << tree;
orchard_commitments.pushKV("finalState", HexStr(s.begin(), s.end()));
} else {
// Set skipHash to the most recent block that has a finalState.
const CBlockIndex* pindex_skip = pindex->pprev;
while (pindex_skip && !pcoinsTip->GetOrchardAnchorAt(pindex_skip->hashFinalOrchardRoot, tree)) {
pindex_skip = pindex_skip->pprev;
}
if (pindex_skip) {
orchard_result.pushKV("skipHash", pindex_skip->GetBlockHash().GetHex());
}
}
orchard_result.pushKV("commitments", orchard_commitments);
res.pushKV("orchard", orchard_result);
}
return res;
}