aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeshCollider <dobsonsa68@gmail.com>2019-08-17 09:23:36 +1200
committerMeshCollider <dobsonsa68@gmail.com>2019-08-17 09:23:52 +1200
commit7a960ba775a60ebcc2e830356693e3ed702b22f1 (patch)
treece69f538a5dc487602264e6a8eda889d4d104dc9
parentb80cdfec9a079b841194c7026faddbd496e1dfc0 (diff)
parent26d3fad1093dfc697048313be7a96c9adf723654 (diff)
Merge #15986: Add checksum to getdescriptorinfo
26d3fad1093dfc697048313be7a96c9adf723654 Add unmodified-but-with-checksum to getdescriptorinfo (Pieter Wuille) 104b3a5069c937383e6f88f2f3fb804ef61b208f Factor out checksum checking from descriptor parsing (Pieter Wuille) Pull request description: ACKs for top commit: achow101: Code Review ACK 26d3fad1093dfc697048313be7a96c9adf723654 meshcollider: re-Code Review ACK 26d3fad1093dfc697048313be7a96c9adf723654 Sjors: ACK 26d3fad1093dfc697048313be7a96c9adf723654 Tree-SHA512: b7a7f89b64a184927d6f9a0c183a087609983f0c5d5593f78e12db4714e930a4af655db9da4b0c407ea2e24d3b926cef6e1f2a15de502d0d1290a6e046826b99
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/script/descriptor.cpp35
-rw-r--r--src/script/descriptor.h8
-rwxr-xr-xtest/functional/wallet_address_types.py4
4 files changed, 39 insertions, 10 deletions
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 6be4057366..d1e9682416 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -136,6 +136,7 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
RPCResult{
"{\n"
" \"descriptor\" : \"desc\", (string) The descriptor in canonical form, without private keys\n"
+ " \"checksum\" : \"chksum\", (string) The checksum for the input descriptor\n"
" \"isrange\" : true|false, (boolean) Whether the descriptor is ranged\n"
" \"issolvable\" : true|false, (boolean) Whether the descriptor is solvable\n"
" \"hasprivatekeys\" : true|false, (boolean) Whether the input descriptor contained at least one private key\n"
@@ -156,6 +157,7 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
result.pushKV("descriptor", desc->ToString());
+ result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str()));
result.pushKV("isrange", desc->IsRange());
result.pushKV("issolvable", desc->IsSolvable());
result.pushKV("hasprivatekeys", provider.keys.size() > 0);
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 327af62a4f..d2b370b65d 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -914,27 +914,42 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
} // namespace
-std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, bool require_checksum)
+/** Check a descriptor checksum, and update desc to be the checksum-less part. */
+bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string* out_checksum = nullptr)
{
- Span<const char> sp(descriptor.data(), descriptor.size());
-
- // Checksum checks
auto check_split = Split(sp, '#');
- if (check_split.size() > 2) return nullptr; // Multiple '#' symbols
- if (check_split.size() == 1 && require_checksum) return nullptr; // Missing checksum
+ if (check_split.size() > 2) return false; // Multiple '#' symbols
+ if (check_split.size() == 1 && require_checksum) return false; // Missing checksum
+ if (check_split.size() == 2) {
+ if (check_split[1].size() != 8) return false; // Unexpected length for checksum
+ }
+ auto checksum = DescriptorChecksum(check_split[0]);
+ if (checksum.empty()) return false; // Invalid characters in payload
if (check_split.size() == 2) {
- if (check_split[1].size() != 8) return nullptr; // Unexpected length for checksum
- auto checksum = DescriptorChecksum(check_split[0]);
- if (checksum.empty()) return nullptr; // Invalid characters in payload
- if (!std::equal(checksum.begin(), checksum.end(), check_split[1].begin())) return nullptr; // Checksum mismatch
+ if (!std::equal(checksum.begin(), checksum.end(), check_split[1].begin())) return false; // Checksum mismatch
}
+ if (out_checksum) *out_checksum = std::move(checksum);
sp = check_split[0];
+ return true;
+}
+std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, bool require_checksum)
+{
+ Span<const char> sp(descriptor.data(), descriptor.size());
+ if (!CheckChecksum(sp, require_checksum)) return nullptr;
auto ret = ParseScript(sp, ParseScriptContext::TOP, out);
if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
return nullptr;
}
+std::string GetDescriptorChecksum(const std::string& descriptor)
+{
+ std::string ret;
+ Span<const char> sp(descriptor.data(), descriptor.size());
+ if (!CheckChecksum(sp, false, &ret)) return "";
+ return ret;
+}
+
std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const SigningProvider& provider)
{
return InferScript(script, ParseScriptContext::TOP, provider);
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index a34e9f0d8a..eae1e262cd 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -81,6 +81,14 @@ struct Descriptor {
*/
std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, bool require_checksum = false);
+/** Get the checksum for a descriptor.
+ *
+ * If it already has one, and it is correct, return the checksum in the input.
+ * If it already has one that is wrong, return "".
+ * If it does not already have one, return the checksum that would need to be added.
+ */
+std::string GetDescriptorChecksum(const std::string& descriptor);
+
/** Find a descriptor for the specified script, using information from provider where possible.
*
* A non-ranged descriptor which only generates the specified script will be returned in all
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index a40613dfc7..4e4ed8f26b 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -175,6 +175,10 @@ class AddressTypeTest(BitcoinTestFramework):
assert info['desc'] == descsum_create(info['desc'][:-9])
# Verify that stripping the checksum and feeding it to getdescriptorinfo roundtrips
assert info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'][:-9])['descriptor']
+ assert_equal(info['desc'][-8:], self.nodes[0].getdescriptorinfo(info['desc'][:-9])['checksum'])
+ # Verify that keeping the checksum and feeding it to getdescriptorinfo roundtrips
+ assert info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'])['descriptor']
+ assert_equal(info['desc'][-8:], self.nodes[0].getdescriptorinfo(info['desc'])['checksum'])
if not multisig and typ == 'legacy':
# P2PKH