@@ -46,6 +46,7 @@ bool fImporting = false;
4646bool fReindex = false ;
4747bool fBenchmark = false ;
4848bool fTxIndex = false ;
49+ bool fAddrIndex = false ;
4950unsigned int nCoinCacheSize = 5000 ;
5051bool fHaveGUI = false ;
5152
@@ -1095,6 +1096,42 @@ bool CWalletTx::AcceptWalletTransaction()
10951096 return false ;
10961097}
10971098
1099+ bool ReadTransaction (CTransaction& tx, const CDiskTxPos &pos, uint256 &hashBlock) {
1100+ CAutoFile file (OpenBlockFile (pos, true ), SER_DISK, CLIENT_VERSION);
1101+ CBlockHeader header;
1102+ try {
1103+ file >> header;
1104+ fseek (file, pos.nTxOffset , SEEK_CUR);
1105+ file >> tx;
1106+ } catch (std::exception &e) {
1107+ return error (" %s() : deserialize or I/O error" , __PRETTY_FUNCTION__);
1108+ }
1109+ hashBlock = header.GetHash ();
1110+ return true ;
1111+ }
1112+
1113+ bool FindTransactionsByDestination (const CTxDestination &dest, std::set<CExtDiskTxPos> &setpos) {
1114+ uint160 addrid = 0 ;
1115+ const CKeyID *pkeyid = boost::get<CKeyID>(&dest);
1116+ if (pkeyid)
1117+ addrid = static_cast <uint160>(*pkeyid);
1118+ if (!addrid) {
1119+ const CScriptID *pscriptid = boost::get<CScriptID>(&dest);
1120+ if (pscriptid)
1121+ addrid = static_cast <uint160>(*pscriptid);
1122+ }
1123+ if (!addrid)
1124+ return false ;
1125+
1126+ LOCK (cs_main);
1127+ if (!fAddrIndex )
1128+ return false ;
1129+ std::vector<CExtDiskTxPos> vPos;
1130+ if (!pblocktree->ReadAddrIndex (addrid, vPos))
1131+ return false ;
1132+ setpos.insert (vPos.begin (), vPos.end ());
1133+ return true ;
1134+ }
10981135
10991136// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
11001137bool GetTransaction (const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow )
@@ -1114,16 +1151,8 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
11141151 if (fTxIndex ) {
11151152 CDiskTxPos postx;
11161153 if (pblocktree->ReadTxIndex (hash, postx)) {
1117- CAutoFile file (OpenBlockFile (postx, true ), SER_DISK, CLIENT_VERSION);
1118- CBlockHeader header;
1119- try {
1120- file >> header;
1121- fseek (file, postx.nTxOffset , SEEK_CUR);
1122- file >> txOut;
1123- } catch (std::exception &e) {
1124- return error (" %s() : deserialize or I/O error" , __PRETTY_FUNCTION__);
1125- }
1126- hashBlock = header.GetHash ();
1154+ if (!ReadTransaction (txOut, postx, hashBlock))
1155+ return false ;
11271156 if (txOut.GetHash () != hash)
11281157 return error (" %s() : txid mismatch" , __PRETTY_FUNCTION__);
11291158 return true ;
@@ -1748,6 +1777,32 @@ void ThreadScriptCheck() {
17481777 scriptcheckqueue.Thread ();
17491778}
17501779
1780+ // Index either: a) every data push >=8 bytes, b) if no such pushes, the entire script
1781+ void static BuildAddrIndex (const CScript &script, const CExtDiskTxPos &pos, std::vector<std::pair<uint160, CExtDiskTxPos> > &out) {
1782+ CScript::const_iterator pc = script.begin ();
1783+ CScript::const_iterator pend = script.end ();
1784+ std::vector<unsigned char > data;
1785+ opcodetype opcode;
1786+ bool fHaveData = false ;
1787+ while (pc < pend) {
1788+ script.GetOp (pc, opcode, data);
1789+ if (0 <= opcode && opcode <= OP_PUSHDATA4 && data.size () >= 8 ) { // data element
1790+ uint160 addrid = 0 ;
1791+ if (data.size () <= 20 ) {
1792+ memcpy (&addrid, &data[0 ], data.size ());
1793+ } else {
1794+ addrid = Hash160 (data);
1795+ }
1796+ out.push_back (std::make_pair (addrid, pos));
1797+ fHaveData = true ;
1798+ }
1799+ }
1800+ if (!fHaveData ) {
1801+ uint160 addrid = Hash160 (script);
1802+ out.push_back (std::make_pair (addrid, pos));
1803+ }
1804+ }
1805+
17511806bool ConnectBlock (CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck )
17521807{
17531808 // Check it again in case a previous version let a bad block in
@@ -1805,10 +1860,14 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
18051860 int64 nFees = 0 ;
18061861 int nInputs = 0 ;
18071862 unsigned int nSigOps = 0 ;
1808- CDiskTxPos pos (pindex->GetBlockPos (), GetSizeOfCompactSize (block.vtx .size ()));
1809- std::vector<std::pair<uint256, CDiskTxPos> > vPos;
1810- vPos.reserve (block.vtx .size ());
1811- for (unsigned int i = 0 ; i < block.vtx .size (); i++)
1863+ CExtDiskTxPos pos (CDiskTxPos (pindex->GetBlockPos (), GetSizeOfCompactSize (block.vtx .size ())), pindex->nHeight );
1864+ std::vector<std::pair<uint256, CDiskTxPos> > vPosTxid;
1865+ std::vector<std::pair<uint160, CExtDiskTxPos> > vPosAddrid;
1866+ if (fTxIndex )
1867+ vPosTxid.reserve (block.vtx .size ());
1868+ if (fAddrIndex )
1869+ vPosAddrid.reserve (4 *block.vtx .size ());
1870+ for (unsigned int i=0 ; i<block.vtx .size (); i++)
18121871 {
18131872 const CTransaction &tx = block.vtx [i];
18141873
@@ -1840,12 +1899,24 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
18401899 control.Add (vChecks);
18411900 }
18421901
1902+ if (fTxIndex )
1903+ vPosTxid.push_back (std::make_pair (block.GetTxHash (i), pos));
1904+ if (fAddrIndex ) {
1905+ if (!tx.IsCoinBase ()) {
1906+ BOOST_FOREACH (const CTxIn &txin, tx.vin ) {
1907+ const CCoins &coins = view.GetCoins (txin.prevout .hash );
1908+ BuildAddrIndex (coins.vout [txin.prevout .n ].scriptPubKey , pos, vPosAddrid);
1909+ }
1910+ }
1911+ BOOST_FOREACH (const CTxOut &txout, tx.vout )
1912+ BuildAddrIndex (txout.scriptPubKey , pos, vPosAddrid);
1913+ }
1914+
18431915 CTxUndo txundo;
18441916 UpdateCoins (tx, state, view, txundo, pindex->nHeight , block.GetTxHash (i));
18451917 if (!tx.IsCoinBase ())
18461918 blockundo.vtxundo .push_back (txundo);
18471919
1848- vPos.push_back (std::make_pair (block.GetTxHash (i), pos));
18491920 pos.nTxOffset += ::GetSerializeSize (tx, SER_DISK, CLIENT_VERSION);
18501921 }
18511922 int64 nTime = GetTimeMicros () - nStart;
@@ -1887,8 +1958,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
18871958 }
18881959
18891960 if (fTxIndex )
1890- if (!pblocktree->WriteTxIndex (vPos ))
1961+ if (!pblocktree->WriteTxIndex (vPosTxid ))
18911962 return state.Abort (_ (" Failed to write transaction index" ));
1963+ if (fAddrIndex )
1964+ if (!pblocktree->AddAddrIndex (vPosAddrid))
1965+ return state.Abort (_ (" Failed to write address index" ));
18921966
18931967 // add this block to the view's block chain
18941968 assert (view.SetBestBlock (pindex));
@@ -2745,6 +2819,9 @@ bool static LoadBlockIndexDB()
27452819 pblocktree->ReadFlag (" txindex" , fTxIndex );
27462820 printf (" LoadBlockIndexDB(): transaction index %s\n " , fTxIndex ? " enabled" : " disabled" );
27472821
2822+ pblocktree->ReadFlag (" addrindex" , fAddrIndex );
2823+ printf (" LoadBlockIndexDB(): address index %s\n " , fAddrIndex ? " enabled" : " disabled" );
2824+
27482825 // Load hashBestChain pointer to end of best chain
27492826 pindexBest = pcoinsTip->GetBestBlock ();
27502827 if (pindexBest == NULL )
@@ -2869,6 +2946,8 @@ bool InitBlockIndex() {
28692946 // Use the provided setting for -txindex in the new database
28702947 fTxIndex = GetBoolArg (" -txindex" , false );
28712948 pblocktree->WriteFlag (" txindex" , fTxIndex );
2949+ fAddrIndex = GetBoolArg (" -addrindex" , false );
2950+ pblocktree->WriteFlag (" addrindex" , fAddrIndex );
28722951 printf (" Initializing databases...\n " );
28732952
28742953 // Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
0 commit comments