From 6fd7ef2bbf1f941c8dee302ffdeb44e603148723 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 7 Feb 2014 02:19:48 +0100 Subject: Also switch the (unused) verification code to low-s instead of even-s. a81cd968 introduced a malleability breaker for signatures (using an even value for S). In e0e14e43 this was changed to the lower of two potential values, rather than the even one. Only the signing code was changed though, the (for now unused) verification code wasn't adapted. --- src/script.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 810ba16d2..84a2a629e 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -296,9 +296,12 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); - if (flags & SCRIPT_VERIFY_EVEN_S) { - if (S[nLenS-1] & 1) - return error("Non-canonical signature: S value odd"); + if (flags & SCRIPT_VERIFY_LOW_S) { + // If the S value is above the order of the curve divided by two, its + // complement modulo the order could have been used instead, which is + // one byte shorter when encoded correctly. + if (!CKey::CheckSignatureElement(S, nLenS, true)) + return error("Non-canonical signature: S value is unnecessarily high"); } return true; -- cgit v1.2.3 From 27bff74e39c4c2951a709114e0d565568a0554fa Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 26 Mar 2014 15:55:35 -0400 Subject: script: switch to CScriptNum usage for scripts --- src/script.cpp | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 810ba16d2..25180e0bb 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -25,22 +25,13 @@ typedef vector valtype; static const valtype vchFalse(0); static const valtype vchZero(0); static const valtype vchTrue(1, 1); -static const CBigNum bnZero(0); -static const CBigNum bnOne(1); -static const CBigNum bnFalse(0); -static const CBigNum bnTrue(1); -static const size_t nMaxNumSize = 4; +static const CScriptNum bnZero(0); +static const CScriptNum bnOne(1); +static const CScriptNum bnFalse(0); +static const CScriptNum bnTrue(1); bool CheckSig(vector vchSig, const vector &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags); -CBigNum CastToBigNum(const valtype& vch) -{ - if (vch.size() > nMaxNumSize) - throw runtime_error("CastToBigNum() : overflow"); - // Get rid of extra leading zeros - return CBigNum(CBigNum(vch).getvch()); -} - bool CastToBool(const valtype& vch) { for (unsigned int i = 0; i < vch.size(); i++) @@ -306,7 +297,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { - CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); @@ -380,7 +370,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_16: { // ( -- value) - CBigNum bn((int)opcode - (int)(OP_1 - 1)); + CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; @@ -556,7 +546,7 @@ bool EvalScript(vector >& stack, const CScript& script, co case OP_DEPTH: { // -- stacksize - CBigNum bn(stack.size()); + CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; @@ -606,7 +596,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CastToBigNum(stacktop(-1)).getint(); + int n = CScriptNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -654,7 +644,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (in -- in size) if (stack.size() < 1) return false; - CBigNum bn(stacktop(-1).size()); + CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; @@ -705,7 +695,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // (in -- out) if (stack.size() < 1) return false; - CBigNum bn = CastToBigNum(stacktop(-1)); + CScriptNum bn(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; @@ -738,9 +728,9 @@ bool EvalScript(vector >& stack, const CScript& script, co // (x1 x2 -- out) if (stack.size() < 2) return false; - CBigNum bn1 = CastToBigNum(stacktop(-2)); - CBigNum bn2 = CastToBigNum(stacktop(-1)); - CBigNum bn; + CScriptNum bn1(stacktop(-2)); + CScriptNum bn2(stacktop(-1)); + CScriptNum bn(0); switch (opcode) { case OP_ADD: @@ -783,9 +773,9 @@ bool EvalScript(vector >& stack, const CScript& script, co // (x min max -- out) if (stack.size() < 3) return false; - CBigNum bn1 = CastToBigNum(stacktop(-3)); - CBigNum bn2 = CastToBigNum(stacktop(-2)); - CBigNum bn3 = CastToBigNum(stacktop(-1)); + CScriptNum bn1(stacktop(-3)); + CScriptNum bn2(stacktop(-2)); + CScriptNum bn3(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); @@ -882,7 +872,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + int nKeysCount = CScriptNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -893,7 +883,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if ((int)stack.size() < i) return false; - int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + int nSigsCount = CScriptNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; -- cgit v1.2.3 From 05e3ecffa495c0905b88cfc92b23bb519b7fe70b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 26 Mar 2014 15:57:21 -0400 Subject: script: remove bignum dependency --- src/script.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 25180e0bb..81d275445 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -5,7 +5,6 @@ #include "script.h" -#include "bignum.h" #include "core.h" #include "hash.h" #include "key.h" -- cgit v1.2.3 From 68f7d1d7af39a8ea6510f888e8e058e8e8faa007 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 10 Mar 2014 17:31:46 -0400 Subject: Create (MANDATORY|STANDARD)_SCRIPT_VERIFY_FLAGS constants --- src/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 810ba16d2..dc0cd28bf 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1670,7 +1670,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) -- cgit v1.2.3 From 6380180821917c22ecfd89128ee60aae6f4cac33 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 10 Mar 2014 17:36:35 -0400 Subject: Add rejection of non-null CHECKMULTISIG dummy values This is a source of transaction mutability as the dummy value was previously not checked and could be modified to something other than the usual OP_0 value. --- src/script.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index dc0cd28bf..a5cdc9712 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -934,8 +934,22 @@ bool EvalScript(vector >& stack, const CScript& script, co fSuccess = false; } - while (i-- > 0) + // Clean up stack of actual arguments + while (i-- > 1) popstack(stack); + + // A bug causes CHECKMULTISIG to consume one extra argument + // whose contents were not checked in any way. + // + // Unfortunately this is a potential source of mutability, + // so optionally verify it is exactly equal to zero prior + // to removing it from the stack. + if (stack.size() < 1) + return false; + if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) + return error("CHECKMULTISIG dummy argument not null"); + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) -- cgit v1.2.3 From aab2c0fd7e7f629b20192ab9f05b281e5783cacc Mon Sep 17 00:00:00 2001 From: Huang Le <4tarhl@gmail.com> Date: Sat, 31 May 2014 01:23:53 +0800 Subject: Remove template matching params from GetOpName() Since they are not real opcodes, being reported as OP_UNKNOWN is less confusing for human-readable decoding. Signed-off-by: Huang Le <4tarhl@gmail.com> --- src/script.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index ac6d4b316..381e84d0b 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -208,14 +208,13 @@ const char* GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + // Note: + // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum + // as kind of implementation hack, they are *NOT* real opcodes. If found in real + // Script, just let the default: case deal with them. - // template matching params - case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; - case OP_PUBKEY : return "OP_PUBKEY"; - case OP_SMALLDATA : return "OP_SMALLDATA"; - - case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: return "OP_UNKNOWN"; } -- cgit v1.2.3 From 6dd5edb7de7f5f9aeac71b676c71186405a15376 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 10 Jun 2014 15:01:23 +0200 Subject: Remove unused Print/PrintHex functions You can just use HexStr(script) or script.ToString() for debugging, no need for these extra functions. --- src/script.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 381e84d0b..11cdfef95 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -838,10 +838,6 @@ bool EvalScript(vector >& stack, const CScript& script, co valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); - ////// debug print - //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); - //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); - // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); -- cgit v1.2.3 From 7b4737c87805b464cd47d01a9d814df5e41b8255 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 26 Apr 2014 19:26:34 +0200 Subject: Switch script.cpp and hash.cpp to use sha2.cpp instead of OpenSSL. --- src/script.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 11cdfef95..f20c0bcca 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -9,10 +9,13 @@ #include "hash.h" #include "key.h" #include "keystore.h" +#include "sha2.h" #include "sync.h" #include "uint256.h" #include "util.h" +#include + #include #include #include @@ -805,17 +808,11 @@ bool EvalScript(vector >& stack, const CScript& script, co else if (opcode == OP_SHA1) SHA1(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA256) - SHA256(&vch[0], vch.size(), &vchHash[0]); + CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_HASH160) - { - uint160 hash160 = Hash160(vch); - memcpy(&vchHash[0], &hash160, sizeof(hash160)); - } + CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_HASH256) - { - uint256 hash = Hash(vch.begin(), vch.end()); - memcpy(&vchHash[0], &hash, sizeof(hash)); - } + CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); popstack(stack); stack.push_back(vchHash); } -- cgit v1.2.3 From 1cc344ce42d8dddd6356c89ef3ceb58418676816 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 28 Apr 2014 03:09:13 +0200 Subject: Add built-in SHA-1 implementation. --- src/script.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index f20c0bcca..facf3044d 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -9,13 +9,12 @@ #include "hash.h" #include "key.h" #include "keystore.h" +#include "sha1.h" #include "sha2.h" #include "sync.h" #include "uint256.h" #include "util.h" -#include - #include #include #include @@ -806,7 +805,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if (opcode == OP_RIPEMD160) RIPEMD160(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA1) - SHA1(&vch[0], vch.size(), &vchHash[0]); + CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_SHA256) CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_HASH160) -- cgit v1.2.3 From 13b5dfef64bbb77d583b2acc59e2b33f89645308 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 28 Apr 2014 12:20:15 +0200 Subject: Move crypto implementations to src/crypto/ --- src/script.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index facf3044d..c6574a6ee 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -9,8 +9,8 @@ #include "hash.h" #include "key.h" #include "keystore.h" -#include "sha1.h" -#include "sha2.h" +#include "crypto/sha1.h" +#include "crypto/sha2.h" #include "sync.h" #include "uint256.h" #include "util.h" -- cgit v1.2.3 From a5bc9c09177420bd1c6a1f9ece9ecfbe80c453fe Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 1 May 2014 00:43:31 +0200 Subject: Add built-in RIPEMD-160 implementation --- src/script.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index c6574a6ee..b383a00a6 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -11,6 +11,7 @@ #include "keystore.h" #include "crypto/sha1.h" #include "crypto/sha2.h" +#include "crypto/ripemd160.h" #include "sync.h" #include "uint256.h" #include "util.h" @@ -803,7 +804,7 @@ bool EvalScript(vector >& stack, const CScript& script, co valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) - RIPEMD160(&vch[0], vch.size(), &vchHash[0]); + CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_SHA1) CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); else if (opcode == OP_SHA256) -- cgit v1.2.3 From 4949004d68dc08382df2c34ae519c1b1cfd60f1a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 7 Jun 2014 13:53:27 +0200 Subject: Add CMutableTransaction and make CTransaction immutable. In addition, introduce a cached hash inside CTransaction, to prevent recalculating it over and over again. --- src/script.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index b383a00a6..c83d26885 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1636,7 +1636,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C } -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType) +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; @@ -1671,7 +1671,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); } -bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) +bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; @@ -1689,7 +1689,7 @@ static CScript PushAll(const vector& values) return result; } -static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, +static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn, const vector& vSolutions, vector& sigs1, vector& sigs2) { -- cgit v1.2.3 From e10dcf27b4fb324a85b5650c7acd2ea5a52e822f Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 24 Jun 2014 14:17:43 +0200 Subject: ensure clean and consistent "namespace" usage - remove some missplaced ; - ensure end of a namespace is clearly visible - use same formatting when using namespace --- src/script.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index c83d26885..dfba4da46 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -974,6 +974,7 @@ bool EvalScript(vector >& stack, const CScript& script, co namespace { + /** Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ @@ -1066,7 +1067,8 @@ public: ::Serialize(s, txTo.nLockTime, nType, nVersion); } }; -} + +} // anon namespace uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { @@ -1092,7 +1094,6 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } - // Valid signature cache, to avoid doing expensive ECDSA signature checking // twice for every transaction (once when accepted into memory pool, and // again when accepted into the block chain) -- cgit v1.2.3 From e44fea55ea73f46bc9460597c7001e77acb58db7 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 21 Feb 2014 04:06:12 +0000 Subject: Add an option to allow users to disable relaying/mining data carrier transactions --- src/script.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index c83d26885..bc4705abe 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1208,7 +1208,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Fri, 26 Jul 2013 01:06:01 +0200 Subject: Add support for watch-only addresses Changes: * Add Add/Have WatchOnly methods to CKeyStore, and implementations in CBasicKeyStore. * Add similar methods to CWallet, and support entries for it in CWalletDB. * Make IsMine in script/wallet return a new enum 'isminetype', rather than a boolean. This allows distinguishing between spendable and unspendable coins. * Add a field fSpendable to COutput (GetAvailableCoins' return type). * Mark watchonly coins in listunspent as 'watchonly': true. * Add 'watchonly' to validateaddress, suppressing script/pubkey/... in this case. Based on a patch by Eric Lombrozo. Conflicts: src/qt/walletmodel.cpp src/rpcserver.cpp src/wallet.cpp --- src/script.cpp | 52 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index e1b698540..0ef012625 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1456,36 +1456,57 @@ public: bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } }; -bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest) { - return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); + if (boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest)) + return MINE_SPENDABLE; + if (keystore.HaveWatchOnly(dest)) + return MINE_WATCH_ONLY; + return MINE_NO; } -bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) +isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector vSolutions; txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + if (!Solver(scriptPubKey, whichType, vSolutions)) { + if (keystore.HaveWatchOnly(scriptPubKey.GetID())) + return MINE_WATCH_ONLY; + return MINE_NO; + } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: - return false; + break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + if (keystore.HaveWatchOnly(keyID)) + return MINE_WATCH_ONLY; + break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - return keystore.HaveKey(keyID); + if (keystore.HaveKey(keyID)) + return MINE_SPENDABLE; + if (keystore.HaveWatchOnly(keyID)) + return MINE_WATCH_ONLY; + break; case TX_SCRIPTHASH: { + CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; - if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) - return false; - return IsMine(keystore, subscript); + if (keystore.GetCScript(scriptID, subscript)) { + isminetype ret = IsMine(keystore, subscript); + if (ret) + return ret; + } + if (keystore.HaveWatchOnly(scriptID)) + return MINE_WATCH_ONLY; + break; } case TX_MULTISIG: { @@ -1495,10 +1516,15 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - return HaveKeys(keys, keystore) == keys.size(); + if (HaveKeys(keys, keystore) == keys.size()) + return MINE_SPENDABLE; + break; } } - return false; + + if (keystore.HaveWatchOnly(scriptPubKey.GetID())) + return MINE_WATCH_ONLY; + return MINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) -- cgit v1.2.3 From d5087d1ba08142bdf135333a0da08ef0f5fc7ef0 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 9 Jun 2014 21:11:59 +0200 Subject: Use script matching rather than destination matching for watch-only. This changes the keystore data format, wallet format and IsMine logic to detect watch-only outputs based on direct script matching rather than first trying to convert outputs to destinations (addresses). The reason is that we don't know how the software that has the spending keys works. It may support the same types of scripts as us, but that is not guaranteed. Furthermore, it removes the ambiguity between addresses used as identifiers for output scripts or identifiers for public keys. One practical implication is that adding a normal pay-to-pubkey-hash address via importaddress will not cause payments to the corresponding full public key to be detected as IsMine. If that is wanted, add those scripts directly (importaddress now also accepts any hex-encoded script). Conflicts: src/wallet.cpp --- src/script.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 0ef012625..89f752bd1 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1456,13 +1456,11 @@ public: bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } }; -isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest) +isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest) { - if (boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest)) - return MINE_SPENDABLE; - if (keystore.HaveWatchOnly(dest)) - return MINE_WATCH_ONLY; - return MINE_NO; + CScript script; + script.SetDestination(dest); + return IsMine(keystore, script); } isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) @@ -1470,7 +1468,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { - if (keystore.HaveWatchOnly(scriptPubKey.GetID())) + if (keystore.HaveWatchOnly(scriptPubKey)) return MINE_WATCH_ONLY; return MINE_NO; } @@ -1485,15 +1483,11 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) return MINE_SPENDABLE; - if (keystore.HaveWatchOnly(keyID)) - return MINE_WATCH_ONLY; break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return MINE_SPENDABLE; - if (keystore.HaveWatchOnly(keyID)) - return MINE_WATCH_ONLY; break; case TX_SCRIPTHASH: { @@ -1501,11 +1495,9 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript); - if (ret) + if (ret == MINE_SPENDABLE) return ret; } - if (keystore.HaveWatchOnly(scriptID)) - return MINE_WATCH_ONLY; break; } case TX_MULTISIG: @@ -1522,7 +1514,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) } } - if (keystore.HaveWatchOnly(scriptPubKey.GetID())) + if (keystore.HaveWatchOnly(scriptPubKey)) return MINE_WATCH_ONLY; return MINE_NO; } -- cgit v1.2.3 From a3e192a3274817517671f624d5744297905e20d2 Mon Sep 17 00:00:00 2001 From: JaSK Date: Tue, 1 Jul 2014 11:00:22 +0200 Subject: replaced MINE_ with ISMINE_ --- src/script.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/script.cpp') diff --git a/src/script.cpp b/src/script.cpp index 89f752bd1..238a25e72 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1469,8 +1469,8 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { if (keystore.HaveWatchOnly(scriptPubKey)) - return MINE_WATCH_ONLY; - return MINE_NO; + return ISMINE_WATCH_ONLY; + return ISMINE_NO; } CKeyID keyID; @@ -1482,12 +1482,12 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) - return MINE_SPENDABLE; + return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) - return MINE_SPENDABLE; + return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: { @@ -1495,7 +1495,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript); - if (ret == MINE_SPENDABLE) + if (ret == ISMINE_SPENDABLE) return ret; } break; @@ -1509,14 +1509,14 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) // in shared-wallet situations. vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); if (HaveKeys(keys, keystore) == keys.size()) - return MINE_SPENDABLE; + return ISMINE_SPENDABLE; break; } } if (keystore.HaveWatchOnly(scriptPubKey)) - return MINE_WATCH_ONLY; - return MINE_NO; + return ISMINE_WATCH_ONLY; + return ISMINE_NO; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) -- cgit v1.2.3