diff options
Diffstat (limited to 'src/script.cpp')
| -rw-r--r-- | src/script.cpp | 420 |
1 files changed, 320 insertions, 100 deletions
diff --git a/src/script.cpp b/src/script.cpp index b6f120289..c29648c2b 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1,12 +1,21 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <boost/foreach.hpp> +#include <boost/tuple/tuple.hpp> using namespace std; using namespace boost; +#include "script.h" +#include "keystore.h" +#include "bignum.h" +#include "key.h" +#include "main.h" +#include "sync.h" +#include "util.h" + bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -32,7 +41,7 @@ CBigNum CastToBigNum(const valtype& vch) bool CastToBool(const valtype& vch) { - for (int i = 0; i < vch.size(); i++) + for (unsigned int i = 0; i < vch.size(); i++) { if (vch[i] != 0) { @@ -530,7 +539,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co return false; int n = CastToBigNum(stacktop(-1)).getint(); popstack(stack); - if (n < 0 || n >= stack.size()) + if (n < 0 || n >= (int)stack.size()) return false; valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) @@ -598,9 +607,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); if (nBegin < 0 || nEnd < nBegin) return false; - if (nBegin > vch.size()) + if (nBegin > (int)vch.size()) nBegin = vch.size(); - if (nEnd > vch.size()) + if (nEnd > (int)vch.size()) nEnd = vch.size(); vch.erase(vch.begin() + nEnd, vch.end()); vch.erase(vch.begin(), vch.begin() + nBegin); @@ -619,7 +628,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co int nSize = CastToBigNum(stacktop(-1)).getint(); if (nSize < 0) return false; - if (nSize > vch.size()) + if (nSize > (int)vch.size()) nSize = vch.size(); if (opcode == OP_LEFT) vch.erase(vch.begin() + nSize, vch.end()); @@ -649,7 +658,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (stack.size() < 1) return false; valtype& vch = stacktop(-1); - for (int i = 0; i < vch.size(); i++) + for (unsigned int i = 0; i < vch.size(); i++) vch[i] = ~vch[i]; } break; @@ -666,17 +675,17 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co MakeSameSize(vch1, vch2); if (opcode == OP_AND) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] &= vch2[i]; } else if (opcode == OP_OR) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] |= vch2[i]; } else if (opcode == OP_XOR) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] ^= vch2[i]; } popstack(stack); @@ -934,7 +943,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; - if (stack.size() < i) + if ((int)stack.size() < i) return false; int nKeysCount = CastToBigNum(stacktop(-i)).getint(); @@ -945,7 +954,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co return false; int ikey = ++i; i += nKeysCount; - if (stack.size() < i) + if ((int)stack.size() < i) return false; int nSigsCount = CastToBigNum(stacktop(-i)).getint(); @@ -953,7 +962,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co return false; int isig = ++i; i += nSigsCount; - if (stack.size() < i) + if ((int)stack.size() < i) return false; // Subset of script starting at the most recent codeseparator @@ -1044,7 +1053,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); // Blank out other inputs' signatures - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) txTmp.vin[i].scriptSig = CScript(); txTmp.vin[nIn].scriptSig = scriptCode; @@ -1055,7 +1064,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int txTmp.vout.clear(); // Let the others update at will - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } @@ -1069,11 +1078,11 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int return 1; } txTmp.vout.resize(nOut+1); - for (int i = 0; i < nOut; i++) + for (unsigned int i = 0; i < nOut; i++) txTmp.vout[i].SetNull(); // Let the others update at will - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } @@ -1086,19 +1095,74 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int } // Serialize and hash - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss.reserve(10000); ss << txTmp << nHashType; return Hash(ss.begin(), ss.end()); } +// 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) + +class CSignatureCache +{ +private: + // sigdata_type is (signature hash, signature, public key): + typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type; + std::set< sigdata_type> setValid; + CCriticalSection cs_sigcache; + +public: + bool + Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) + { + LOCK(cs_sigcache); + + sigdata_type k(hash, vchSig, pubKey); + std::set<sigdata_type>::iterator mi = setValid.find(k); + if (mi != setValid.end()) + return true; + return false; + } + + void + Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) + { + // DoS prevention: limit cache size to less than 10MB + // (~200 bytes per cache entry times 50,000 entries) + // Since there are a maximum of 20,000 signature operations per block + // 50,000 is a reasonable default. + int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + LOCK(cs_sigcache); + + while (static_cast<int64>(setValid.size()) > nMaxCacheSize) + { + // Evict a random entry. Random because that helps + // foil would-be DoS attackers who might try to pre-generate + // and re-use a set of valid signatures just-slightly-greater + // than our cache size. + uint256 randomHash = GetRandHash(); + std::vector<unsigned char> unused; + std::set<sigdata_type>::iterator it = + setValid.lower_bound(sigdata_type(randomHash, unused, unused)); + if (it == setValid.end()) + it = setValid.begin(); + setValid.erase(*it); + } + + sigdata_type k(hash, vchSig, pubKey); + setValid.insert(k); + } +}; + bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; + static CSignatureCache signatureCache; // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) @@ -1109,7 +1173,20 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc return false; vchSig.pop_back(); - return key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig); + uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); + + if (signatureCache.Get(sighash, vchSig, vchPubKey)) + return true; + + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + + if (!key.Verify(sighash, vchSig)) + return false; + + signatureCache.Set(sighash, vchSig, vchPubKey); + return true; } @@ -1235,7 +1312,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi } -bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) { CKey key; if (!keystore.GetKey(address, key)) @@ -1254,16 +1331,12 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2 { int nSigned = 0; int nRequired = multisigdata.front()[0]; - for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++) + for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) { - const valtype& pubkey = *it; - CBitcoinAddress address; - address.SetPubKey(pubkey); - if (Sign1(address, keystore, hash, nHashType, scriptSigRet)) - { + const valtype& pubkey = multisigdata[i]; + CKeyID keyID = CPubKey(pubkey).GetID(); + if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) ++nSigned; - if (nSigned == nRequired) break; - } } return nSigned==nRequired; } @@ -1283,22 +1356,22 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; - CBitcoinAddress address; + CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: return false; case TX_PUBKEY: - address.SetPubKey(vSolutions[0]); - return Sign1(address, keystore, hash, nHashType, scriptSigRet); + keyID = CPubKey(vSolutions[0]).GetID(); + return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); case TX_PUBKEYHASH: - address.SetHash160(uint160(vSolutions[0])); - if (!Sign1(address, keystore, hash, nHashType, scriptSigRet)) + keyID = CKeyID(uint160(vSolutions[0])); + if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) return false; else { - valtype vch; - keystore.GetPubKey(address, vch); + CPubKey vch; + keystore.GetPubKey(keyID, vch); scriptSigRet << vch; } return true; @@ -1354,19 +1427,35 @@ bool IsStandard(const CScript& scriptPubKey) } -int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) +unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) { - int nResult = 0; + unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) { - CBitcoinAddress address; - address.SetPubKey(pubkey); - if (keystore.HaveKey(address)) + CKeyID keyID = CPubKey(pubkey).GetID(); + if (keystore.HaveKey(keyID)) ++nResult; } return nResult; } + +class CKeyStoreIsMineVisitor : public boost::static_visitor<bool> +{ +private: + const CKeyStore *keystore; +public: + CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { } + bool operator()(const CNoDestination &dest) const { return false; } + bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); } + bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } +}; + +bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +{ + return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); +} + bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { vector<valtype> vSolutions; @@ -1374,21 +1463,21 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) if (!Solver(scriptPubKey, whichType, vSolutions)) return false; - CBitcoinAddress address; + CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: return false; case TX_PUBKEY: - address.SetPubKey(vSolutions[0]); - return keystore.HaveKey(address); + keyID = CPubKey(vSolutions[0]).GetID(); + return keystore.HaveKey(keyID); case TX_PUBKEYHASH: - address.SetHash160(uint160(vSolutions[0])); - return keystore.HaveKey(address); + keyID = CKeyID(uint160(vSolutions[0])); + return keystore.HaveKey(keyID); case TX_SCRIPTHASH: { CScript subscript; - if (!keystore.GetCScript(uint160(vSolutions[0]), subscript)) + if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) return false; return IsMine(keystore, subscript); } @@ -1406,7 +1495,7 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return false; } -bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet) +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector<valtype> vSolutions; txnouttype whichType; @@ -1415,24 +1504,24 @@ bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet) if (whichType == TX_PUBKEY) { - addressRet.SetPubKey(vSolutions[0]); + addressRet = CPubKey(vSolutions[0]).GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { - addressRet.SetHash160(uint160(vSolutions[0])); + addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { - addressRet.SetScriptHash160(uint160(vSolutions[0])); + addressRet = CScriptID(uint160(vSolutions[0])); return true; } // Multisig txns have more than one address... return false; } -bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet) +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; @@ -1443,24 +1532,18 @@ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<C if (typeRet == TX_MULTISIG) { nRequiredRet = vSolutions.front()[0]; - int n = vSolutions.back()[0]; - for (int i = 1; i < vSolutions.size()-1; i++) + for (unsigned int i = 1; i < vSolutions.size()-1; i++) { - CBitcoinAddress address; - address.SetPubKey(vSolutions[i]); + CTxDestination address = CPubKey(vSolutions[i]).GetID(); addressRet.push_back(address); } } else { nRequiredRet = 1; - CBitcoinAddress address; - if (typeRet == TX_PUBKEYHASH) - address.SetHash160(uint160(vSolutions.front())); - else if (typeRet == TX_SCRIPTHASH) - address.SetScriptHash160(uint160(vSolutions.front())); - else if (typeRet == TX_PUBKEY) - address.SetPubKey(vSolutions.front()); + CTxDestination address; + if (!ExtractDestination(scriptPubKey, address)) + return false; addressRet.push_back(address); } @@ -1504,19 +1587,17 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C } -bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; - assert(txin.prevout.n < txFrom.vout.size()); - const CTxOut& txout = txFrom.vout[txin.prevout.n]; // Leave out the signature from the hash, since a signature can't sign itself. // The checksig op will also drop the signatures from its hash. - uint256 hash = SignatureHash(txout.scriptPubKey, txTo, nIn, nHashType); + uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType); txnouttype whichType; - if (!Solver(keystore, txout.scriptPubKey, hash, nHashType, txin.scriptSig, whichType)) + if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType)) return false; if (whichType == TX_SCRIPTHASH) @@ -1528,21 +1609,28 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans // Recompute txn hash using subscript in place of scriptPubKey: uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType); + txnouttype subType; - if (!Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType)) - return false; - if (subType == TX_SCRIPTHASH) - return false; - txin.scriptSig << static_cast<valtype>(subscript); // Append serialized subscript + bool fSolved = + Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH; + // Append serialized subscript whether or not it is completely signed: + txin.scriptSig << static_cast<valtype>(subscript); + if (!fSolved) return false; } // Test solution - if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, true, 0)) - return false; - - return true; + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, 0); } +bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) +{ + assert(nIn < txTo.vin.size()); + CTxIn& txin = txTo.vin[nIn]; + assert(txin.prevout.n < txFrom.vout.size()); + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); +} bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType) { @@ -1555,15 +1643,134 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig if (txin.prevout.hash != txFrom.GetHash()) return false; - if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType)) - return false; + return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType); +} - return true; +static CScript PushAll(const vector<valtype>& values) +{ + CScript result; + BOOST_FOREACH(const valtype& v, values) + result << v; + return result; } -int CScript::GetSigOpCount(bool fAccurate) const +static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const vector<valtype>& vSolutions, + vector<valtype>& sigs1, vector<valtype>& sigs2) { - int n = 0; + // Combine all the signatures we've got: + set<valtype> allsigs; + BOOST_FOREACH(const valtype& v, sigs1) + { + if (!v.empty()) + allsigs.insert(v); + } + BOOST_FOREACH(const valtype& v, sigs2) + { + if (!v.empty()) + allsigs.insert(v); + } + + // Build a map of pubkey -> signature by matching sigs to pubkeys: + assert(vSolutions.size() > 1); + unsigned int nSigsRequired = vSolutions.front()[0]; + unsigned int nPubKeys = vSolutions.size()-2; + map<valtype, valtype> sigs; + BOOST_FOREACH(const valtype& sig, allsigs) + { + for (unsigned int i = 0; i < nPubKeys; i++) + { + const valtype& pubkey = vSolutions[i+1]; + if (sigs.count(pubkey)) + continue; // Already got a sig for this pubkey + + if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) + { + sigs[pubkey] = sig; + break; + } + } + } + // Now build a merged CScript: + unsigned int nSigsHave = 0; + CScript result; result << OP_0; // pop-one-too-many workaround + for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) + { + if (sigs.count(vSolutions[i+1])) + { + result << sigs[vSolutions[i+1]]; + ++nSigsHave; + } + } + // Fill any missing with OP_0: + for (unsigned int i = nSigsHave; i < nSigsRequired; i++) + result << OP_0; + + return result; +} + +static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const txnouttype txType, const vector<valtype>& vSolutions, + vector<valtype>& sigs1, vector<valtype>& sigs2) +{ + switch (txType) + { + case TX_NONSTANDARD: + // Don't know anything about this, assume bigger one is correct: + if (sigs1.size() >= sigs2.size()) + return PushAll(sigs1); + return PushAll(sigs2); + case TX_PUBKEY: + case TX_PUBKEYHASH: + // Signatures are bigger than placeholders or empty scripts: + if (sigs1.empty() || sigs1[0].empty()) + return PushAll(sigs2); + return PushAll(sigs1); + case TX_SCRIPTHASH: + if (sigs1.empty() || sigs1.back().empty()) + return PushAll(sigs2); + else if (sigs2.empty() || sigs2.back().empty()) + return PushAll(sigs1); + else + { + // Recurse to combine: + valtype spk = sigs1.back(); + CScript pubKey2(spk.begin(), spk.end()); + + txnouttype txType2; + vector<vector<unsigned char> > vSolutions2; + Solver(pubKey2, txType2, vSolutions2); + sigs1.pop_back(); + sigs2.pop_back(); + CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); + result << spk; + return result; + } + case TX_MULTISIG: + return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); + } + + return CScript(); +} + +CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const CScript& scriptSig1, const CScript& scriptSig2) +{ + txnouttype txType; + vector<vector<unsigned char> > vSolutions; + Solver(scriptPubKey, txType, vSolutions); + + vector<valtype> stack1; + EvalScript(stack1, scriptSig1, CTransaction(), 0, 0); + vector<valtype> stack2; + EvalScript(stack2, scriptSig2, CTransaction(), 0, 0); + + return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); +} + +unsigned int CScript::GetSigOpCount(bool fAccurate) const +{ + unsigned int n = 0; const_iterator pc = begin(); opcodetype lastOpcode = OP_INVALIDOPCODE; while (pc < end()) @@ -1585,7 +1792,7 @@ int CScript::GetSigOpCount(bool fAccurate) const return n; } -int CScript::GetSigOpCount(const CScript& scriptSig) const +unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const { if (!IsPayToScriptHash()) return GetSigOpCount(true); @@ -1618,13 +1825,34 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } -void CScript::SetBitcoinAddress(const CBitcoinAddress& address) +class CScriptVisitor : public boost::static_visitor<bool> { - this->clear(); - if (address.IsScript()) - *this << OP_HASH160 << address.GetHash160() << OP_EQUAL; - else - *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG; +private: + CScript *script; +public: + CScriptVisitor(CScript *scriptin) { script = scriptin; } + + bool operator()(const CNoDestination &dest) const { + script->clear(); + return false; + } + + bool operator()(const CKeyID &keyID) const { + script->clear(); + *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG; + return true; + } + + bool operator()(const CScriptID &scriptID) const { + script->clear(); + *script << OP_HASH160 << scriptID << OP_EQUAL; + return true; + } +}; + +void CScript::SetDestination(const CTxDestination& dest) +{ + boost::apply_visitor(CScriptVisitor(this), dest); } void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) @@ -1636,11 +1864,3 @@ void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys) *this << key.GetPubKey(); *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; } - -void CScript::SetPayToScriptHash(const CScript& subscript) -{ - assert(!subscript.empty()); - uint160 subscriptHash = Hash160(subscript); - this->clear(); - *this << OP_HASH160 << subscriptHash << OP_EQUAL; -} |