aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/ismine.cpp3
-rw-r--r--src/script/sign.cpp65
-rw-r--r--src/script/sign.h49
-rw-r--r--src/script/standard.cpp57
-rw-r--r--src/script/standard.h5
5 files changed, 105 insertions, 74 deletions
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index e3a6278c7..1433ebf42 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
IsMineResult ret = IsMineResult::NO;
std::vector<valtype> vSolutions;
- txnouttype whichType;
- Solver(scriptPubKey, whichType, vSolutions);
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
CKeyID keyID;
switch (whichType)
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 1982e8a83..d77991042 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -50,10 +50,6 @@ static bool GetCScript(const SigningProvider& provider, const SignatureData& sig
static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
{
- if (provider.GetPubKey(address, pubkey)) {
- sigdata.misc_pubkeys.emplace(pubkey.GetID(), pubkey);
- return true;
- }
// Look for pubkey in all partial sigs
const auto it = sigdata.signatures.find(address);
if (it != sigdata.signatures.end()) {
@@ -63,7 +59,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c
// Look for pubkey in pubkey list
const auto& pk_it = sigdata.misc_pubkeys.find(address);
if (pk_it != sigdata.misc_pubkeys.end()) {
- pubkey = pk_it->second;
+ pubkey = pk_it->second.first;
+ return true;
+ }
+ // Query the underlying provider
+ if (provider.GetPubKey(address, pubkey)) {
+ KeyOriginInfo info;
+ if (provider.GetKeyOrigin(address, info)) {
+ sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info)));
+ }
return true;
}
return false;
@@ -101,8 +105,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<unsigned char> sig;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
- return false;
+ whichTypeRet = Solver(scriptPubKey, vSolutions);
switch (whichTypeRet)
{
@@ -233,7 +236,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
return sigdata.complete;
}
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash)
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
{
// if this input has a final scriptsig or scriptwitness, don't do anything with it
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
@@ -241,6 +244,7 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
}
// Fill SignatureData with input info
+ SignatureData sigdata;
input.FillSignatureData(sigdata);
// Get UTXO
@@ -272,6 +276,16 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return false;
input.FromSignatureData(sigdata);
+
+ // If both UTXO types are present, drop the unnecessary one.
+ if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
+ if (sigdata.witness) {
+ input.non_witness_utxo = nullptr;
+ } else {
+ input.witness_utxo.SetNull();
+ }
+ }
+
return sig_complete;
}
@@ -329,9 +343,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
}
// Get scripts
- txnouttype script_type;
std::vector<std::vector<unsigned char>> solutions;
- Solver(txout.scriptPubKey, script_type, solutions);
+ txnouttype script_type = Solver(txout.scriptPubKey, solutions);
SigVersion sigversion = SigVersion::BASE;
CScript next_script = txout.scriptPubKey;
@@ -342,7 +355,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(redeem_script);
// Get redeemScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.script.pop_back();
}
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
@@ -352,7 +365,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(witness_script);
// Get witnessScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.witness.pop_back();
stack.script = std::move(stack.witness);
stack.witness.clear();
@@ -543,7 +556,7 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -571,6 +584,9 @@ void PSBTInput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
void PSBTInput::Merge(const PSBTInput& input)
@@ -612,7 +628,7 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -624,6 +640,9 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
bool PSBTOutput::IsNull() const
@@ -640,14 +659,26 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
}
-bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& script) const
+bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
{
return m_provider->GetCScript(scriptid, script);
}
-bool PublicOnlySigningProvider::GetPubKey(const CKeyID &address, CPubKey& pubkey) const
+bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
+{
+ return m_provider->GetPubKey(keyid, pubkey);
+}
+
+bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
+{
+ if (m_hide_secret) return false;
+ return m_provider->GetKey(keyid, key);
+}
+
+bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
- return m_provider->GetPubKey(address, pubkey);
+ if (m_hide_origin) return false;
+ return m_provider->GetKeyOrigin(keyid, info);
}
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
diff --git a/src/script/sign.h b/src/script/sign.h
index 7ade715ee..18b732099 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -20,6 +20,12 @@ class CTransaction;
struct CMutableTransaction;
+struct KeyOriginInfo
+{
+ unsigned char fingerprint[4];
+ std::vector<uint32_t> path;
+};
+
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
@@ -28,19 +34,24 @@ public:
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
-class PublicOnlySigningProvider : public SigningProvider
+class HidingSigningProvider : public SigningProvider
{
private:
+ const bool m_hide_secret;
+ const bool m_hide_origin;
const SigningProvider* m_provider;
public:
- PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {}
- bool GetCScript(const CScriptID &scriptid, CScript& script) const;
- bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const;
+ HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
+ bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
+ bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKey(const CKeyID& keyid, CKey& key) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
struct FlatSigningProvider final : public SigningProvider
@@ -98,7 +109,7 @@ struct SignatureData {
CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
- std::map<CKeyID, CPubKey> misc_pubkeys;
+ std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
@@ -155,7 +166,7 @@ void UnserializeFromVector(Stream& s, X&... args)
// Deserialize HD keypaths into a map
template<typename Stream>
-void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
+void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
// Make sure that the key is the size of pubkey + 1
if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) {
@@ -172,25 +183,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std
// Read in key path
uint64_t value_len = ReadCompactSize(s);
- std::vector<uint32_t> keypath;
- for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) {
+ if (value_len % 4 || value_len == 0) {
+ throw std::ios_base::failure("Invalid length for HD key path");
+ }
+
+ KeyOriginInfo keypath;
+ s >> keypath.fingerprint;
+ for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
uint32_t index;
s >> index;
- keypath.push_back(index);
+ keypath.path.push_back(index);
}
// Add to map
- hd_keypaths.emplace(pubkey, keypath);
+ hd_keypaths.emplace(pubkey, std::move(keypath));
}
// Serialize HD keypaths to a stream from a map
template<typename Stream>
-void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
+void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
{
for (auto keypath_pair : hd_keypaths) {
SerializeToVector(s, type, MakeSpan(keypath_pair.first));
- WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t));
- for (auto& path : keypath_pair.second) {
+ WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
+ s << keypath_pair.second.fingerprint;
+ for (const auto& path : keypath_pair.second.path) {
s << path;
}
}
@@ -205,7 +222,7 @@ struct PSBTInput
CScript witness_script;
CScript final_script_sig;
CScriptWitness final_script_witness;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<CKeyID, SigPair> partial_sigs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
int sighash_type = 0;
@@ -418,7 +435,7 @@ struct PSBTOutput
{
CScript redeem_script;
CScript witness_script;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
bool IsNull() const;
@@ -687,7 +704,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1);
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index bfbf9f13d..08ba1b1e0 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
return (it + 1 == script.end());
}
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
{
vSolutionsRet.clear();
@@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
if (scriptPubKey.IsPayToScriptHash())
{
- typeRet = TX_SCRIPTHASH;
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
- return true;
+ return TX_SCRIPTHASH;
}
int witnessversion;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
- typeRet = TX_WITNESS_V0_KEYHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_KEYHASH;
}
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
- typeRet = TX_WITNESS_V0_SCRIPTHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_SCRIPTHASH;
}
if (witnessversion != 0) {
- typeRet = TX_WITNESS_UNKNOWN;
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
vSolutionsRet.push_back(std::move(witnessprogram));
- return true;
+ return TX_WITNESS_UNKNOWN;
}
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
// Provably prunable, data-carrying output
@@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// byte passes the IsPushOnly() test we don't care what exactly is in the
// script.
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
- typeRet = TX_NULL_DATA;
- return true;
+ return TX_NULL_DATA;
}
std::vector<unsigned char> data;
if (MatchPayToPubkey(scriptPubKey, data)) {
- typeRet = TX_PUBKEY;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEY;
}
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
- typeRet = TX_PUBKEYHASH;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEYHASH;
}
unsigned int required;
std::vector<std::vector<unsigned char>> keys;
if (MatchMultisig(scriptPubKey, required, keys)) {
- typeRet = TX_MULTISIG;
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
- return true;
+ return TX_MULTISIG;
}
vSolutionsRet.clear();
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
std::vector<valtype> vSolutions;
- txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_PUBKEY)
- {
+ if (whichType == TX_PUBKEY) {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;
@@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
- typeRet = TX_NONSTANDARD;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, typeRet, vSolutions))
+ typeRet = Solver(scriptPubKey, vSolutions);
+ if (typeRet == TX_NONSTANDARD) {
return false;
- if (typeRet == TX_NULL_DATA){
+ } else if (typeRet == TX_NULL_DATA) {
// This is data, not addresses
return false;
}
@@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
CScript GetScriptForWitness(const CScript& redeemscript)
{
- txnouttype typ;
std::vector<std::vector<unsigned char> > vSolutions;
- if (Solver(redeemscript, typ, vSolutions)) {
- if (typ == TX_PUBKEY) {
- return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
- } else if (typ == TX_PUBKEYHASH) {
- return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
- }
+ txnouttype typ = Solver(redeemscript, vSolutions);
+ if (typ == TX_PUBKEY) {
+ return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
+ } else if (typ == TX_PUBKEYHASH) {
+ return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
}
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
}
diff --git a/src/script/standard.h b/src/script/standard.h
index b16ac83e7..fc20fb6a0 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t);
* script hash, for P2PKH it will contain the key hash, etc.
*
* @param[in] scriptPubKey Script to parse
- * @param[out] typeRet The script type
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
- * @return True if script matches standard template
+ * @return The script type. TX_NONSTANDARD represents a failed solve.
*/
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet);
/**
* Parse a standard scriptPubKey for the destination address. Assigns result to