diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 548a17fa1b6f0..a96a2407a5d2b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -78,6 +78,7 @@ BITCOIN_TESTS =\ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/script_P2SH_tests.cpp \ + test/script_P2PK_tests.cpp \ test/script_P2PKH_tests.cpp \ test/script_tests.cpp \ test/scriptnum_tests.cpp \ diff --git a/src/script/script.cpp b/src/script/script.cpp index 02a3d2378b9f7..c87fce436d4ec 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -220,6 +220,21 @@ bool CScript::IsPayToScriptHash() const (*this)[22] == OP_EQUAL); } +bool CScript::IsPayToPublicKey() const +{ + // Test for pay-to-pubkey CScript with both + // compressed or uncompressed pubkey + if (this->size() == 35) { + return ((*this)[1] == 0x02 || (*this)[1] == 0x03) && + (*this)[34] == OP_CHECKSIG; + } + if (this->size() == 67) { + return (*this)[1] == 0x04 && + (*this)[66] == OP_CHECKSIG; + } + return false; +} + bool CScript::IsPushOnly(const_iterator pc) const { while (pc < end()) diff --git a/src/script/script.h b/src/script/script.h index 3b53a38ce6b56..f2650456ba4c8 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -624,6 +624,9 @@ class CScript : public CScriptBase bool IsPayToScriptHash() const; + /** Used for obsolete pay-to-pubkey addresses indexing. */ + bool IsPayToPublicKey() const; + /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly(const_iterator pc) const; bool IsPushOnly() const; diff --git a/src/test/script_P2PK_tests.cpp b/src/test/script_P2PK_tests.cpp new file mode 100644 index 0000000000000..e1d9a427e89d9 --- /dev/null +++ b/src/test/script_P2PK_tests.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2012-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "script/script.h" +#include "test/test_dash.h" + +#include + +using namespace std; + +BOOST_FIXTURE_TEST_SUITE(script_P2PK_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(IsPayToPublicKey) +{ + // Test CScript::IsPayToPublicKey() + static const unsigned char p2pkcompressedeven[] = { + 0x41, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_CHECKSIG + }; + BOOST_CHECK(CScript(p2pkcompressedeven, p2pkcompressedeven+sizeof(p2pkcompressedeven)).IsPayToPublicKey()); + + static const unsigned char p2pkcompressedodd[] = { + 0x41, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_CHECKSIG + }; + BOOST_CHECK(CScript(p2pkcompressedodd, p2pkcompressedodd+sizeof(p2pkcompressedodd)).IsPayToPublicKey()); + + static const unsigned char p2pkuncompressed[] = { + 0x41, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_CHECKSIG + }; + BOOST_CHECK(CScript(p2pkuncompressed, p2pkuncompressed+sizeof(p2pkuncompressed)).IsPayToPublicKey()); + + static const unsigned char missingop[] = { + 0x41, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + BOOST_CHECK(!CScript(missingop, missingop+sizeof(missingop)).IsPayToPublicKey()); + + static const unsigned char wrongop[] = { + 0x41, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_EQUALVERIFY + }; + BOOST_CHECK(!CScript(wrongop, wrongop+sizeof(wrongop)).IsPayToPublicKey()); + + static const unsigned char tooshort[] = { + 0x41, 0x02, 0, 0, OP_CHECKSIG + }; + BOOST_CHECK(!CScript(tooshort, tooshort+sizeof(tooshort)).IsPayToPublicKey()); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 06623908bbcde..2401d612aa12f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -17,6 +17,7 @@ #include "utilmoneystr.h" #include "utiltime.h" #include "version.h" +#include "hash.h" using namespace std; @@ -458,6 +459,12 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(make_pair(key, delta)); inserted.push_back(key); + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + uint160 hashBytes(Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.end()-1)); + CMempoolAddressDeltaKey key(1, hashBytes, txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(make_pair(key, delta)); + inserted.push_back(key); } } @@ -474,6 +481,12 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0); mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); inserted.push_back(key); + } else if (out.scriptPubKey.IsPayToPublicKey()) { + uint160 hashBytes(Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.end()-1)); + std::pair ret; + CMempoolAddressDeltaKey key(1, hashBytes, txhash, k, 0); + mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); } } @@ -531,6 +544,9 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { addressHash = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); addressType = 1; + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + addressHash = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.end()-1); + addressType = 1; } else { addressHash.SetNull(); addressType = 0; diff --git a/src/validation.cpp b/src/validation.cpp index 37295058ca2e8..b82926e785145 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1753,6 +1753,10 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // undo unspent index addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue())); + } else if (out.scriptPubKey.IsPayToPublicKey()) { + uint160 hashBytes(Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.end()-1)); + addressIndex.push_back(make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, hash, k, false), out.nValue)); + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, hashBytes, hash, k), CAddressUnspentValue())); } else { continue; } @@ -1817,6 +1821,10 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // restore unspent index addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undoHeight))); + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + uint160 hashBytes(Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.end()-1)); + addressIndex.push_back(make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, hash, j, false), prevout.nValue)); + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, hashBytes, hash, j), CAddressUnspentValue())); } else { continue; } @@ -2158,6 +2166,9 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { hashBytes = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); addressType = 1; + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + hashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.end()-1); + addressType = 1; } else { hashBytes.SetNull(); addressType = 0; @@ -2223,6 +2234,10 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd // record unspent output addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); + } else if (out.scriptPubKey.IsPayToPublicKey()) { + uint160 hashBytes(Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.end()-1)); + addressIndex.push_back(make_pair(CAddressIndexKey(1, hashBytes, pindex->nHeight, i, txhash, k, false), out.nValue)); + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, hashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); } else { continue; }