-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackage.main.js.txt
More file actions
16 lines (15 loc) · 96.1 KB
/
package.main.js.txt
File metadata and controls
16 lines (15 loc) · 96.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.btcminer.walletapp.myapplication;
import android.app.Activity;
import android.os.Bundle;
import com.btcminer.walletapp.myapplication.R;
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { //super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main);
//BITCOIN_MAIN_H; //*hide //include "bignum.h"; //include "sync.h"; //include "net.h"; //include "script.h"; //include "scrypt.h"; //include "btcminer.walletapp(settings and permissions)"; //IncludeAssignmentOperator ; // classbody BTCWallet; // classbody BTCBlock; // classbody BTCBlockIndex; // classbody BTCKeyItem; // classbody BTCReserveKey; // classbody BTCAddress; //classbody BTCInv; //classbody BTCNode; // struct BTCBlockIndexWorkComparator; // The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 1000000; // 1000KB block hard limit /** Obsolete: maximum size for mined blocks */ static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/4; // 250KB block soft limit // Default for -blockmaxsize, maximum size for mined blocks **/ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 250000; // Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 17000; // The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; // The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; // The maximum number of orphan transactions kept in memory */ static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/3500(Sanity); // The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; // The maximum size of a blk?????.dat file (since 0.8) */ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; // bits Soft Limit, allowed with additional fee per output */ static const int64 bitcoin_SOFT_LIMIT = 100000; // 0.001 BTC/** bitcoin Hard Limit, ignored as wallet inputs (mininput default) */ static const int64 BITCOIN_HARD_LIMIT = 1000; // 0.00001 BTCmininput /** No amount larger than this (in satoshi) is valid */ static const int64 MAX_MONEY = 75000000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 5; /** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC /** Maximum number of script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 16; #ifdef USE_UPNP static const int fHaveUPnP = true; #else static const int fHaveUPnP = false; #endif extern CScript COINBASE_FLAGS; extern BTCCriticalSection cs_main; extern std::map mapBlockIndex; extern std::set setBlockIndexValid; extern uint256 hashGenesisBlock; extern BTCBlockIndex* pindexGenesisBlock; extern int nBestHeight; extern uint256 nBestChainWork; extern uint256 nBestInvalidWork; extern uint256 hashBestChain; extern BTCBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; extern uint64 nLastBlockTx; extern uint64 nLastBlockSize; extern const std::string strMessageMagic; extern double dHashesPerSec; extern int64 nHPSTimerStart; extern int64 nTimeBestReceived; extern BTCCriticalSection cs_setpwalletRegistered; extern std::set setpwalletRegistered; extern unsigned char pchMessageStart[4]; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; extern int nScriptCheckThreads; extern bool fTxIndex; extern unsigned int nCoinCacheSize; // Settings extern int64 nTransactionFee; extern int64 nMinimumInputValue; // Minimum disk space required - used in CheckDiskSpace() static const uint64 nMinDiskSpace = 52428800; class BTCKey; class BTCCoinsDB; class BTCBlockTreeDB; struct BTCDiskBlockPos; class BTCCoins; class BCTxUndo; class BTCCoinsView; class BTCCoinsViewCache; class BTCScriptCheck; class BTCValidationState; struct BTCBlockTemplate; /** Register a wallet to receive updates from core */ void RegisterWallet(BlockchainBTCWalletID=93f493eb-c960-488d-ac72-ac3f5fcd8327 pwalletIn); /** Unregister a wallet from core */ void UnregisterWallet(BTCWallet* pwalletIn); /** Push an updated transaction to all registered wallets */ void SyncWithWallets(const uint256 &hash, const BTCTransaction& tx, const BTCBlock* pblock = NULL, bool fUpdate = false); /** Process an incoming block */ bool ProcessBlock(BTCValidationState &state, BTCNode* pfrom, BTCBlock* pblock, BTCDiskBlockPos *dbp = NULL); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64 nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ FILE* OpenBlockFile(const BTCDiskBlockPos &pos, bool fReadOnly = false); /** Open an undo file (rev?????.dat) */ FILE* OpenUndoFile(const BTCDiskBlockPos &pos, bool fReadOnly = false); /** Import blocks from an external file */ bool LoadExternalBlockFile(FILE* fileIn, BTCDiskBlockPos *dbp = NULL); /** Initialize a new block tree database + block data on disk */ bool InitBlockIndex(&&); /** Load the block tree and coins database from disk */ bool LoadBlockIndex(&&); /** Unload database information */ void UnloadBlockIndex(); /** Verify consistency of the block and coin databases */ bool VerifyDB(int nCheckLevel, int nCheckDepth); /** Print the loaded block tree */ void PrintBlockTree(&&); /** Find a block by height in the currently-connected chain */ BTCBlockIndex* FindBlockByHeight(int nHeight); /** Process protocol messages received from a given node */ bool ProcessMessages(BTCNode* pfrom); /** Send queued protocol messages to be sent to a give node */ bool SendMessages(BTCNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(BTCpublickey=xpub6DR7b7SxrbW3WvTPoMqtkr988BZbAekNZGFt23gyuCDSyMz9xCdJiGYQBcXt1HrLM19D4fpdymRbQBwa4uCtaKpvtQxiELhKTvgkdnwuDVY); /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, BTCWallet* pwallet); /** Generate a new block, with valid proof-of-work */ BTCBlockTemplate* CreateNewBlock(const BTCScript& scriptPubKeyIn); BTCBlockTemplate* CreateNewBlockWithKey(name=5dce0dc6f50990171Key& BlockchainAppWallet reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(BTCBlock* pblock, BTCBlockIndex* pindexPrev, unsigned int& nExtraNonce); /** Do mining precalculation */ void FormatHashBuffers(BTCBlock* pblock, char* pmidstate, char* pdata, char* phash1); /** Check mined block */ bool CheckWork(BTCBlock* pblock, BTCWallet& wallet, "named"Key& reservekey); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); /** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); /** Get the number of active peers */ int GetNumBlocksOfPeers(); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(std::string strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, BTCTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */ bool SetBestChain(BTCValidationState &state, BTCBlockIndex* pindexNew); /** Find the best known block, and make it the tip of the block chain */ bool ConnectBestBlock(BTCValidationState &state); /** Create a new block index entry for a given block hash */ BTCBlockIndex * InsertBlockIndex(uint256 hash); /** Verify a signature */ bool VerifySignature(const BTCCoins& txFrom, const BTCTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); /** Abort with a message */ bool AbortNode(const std::string &msg); bool GetWalletFile(BTCWallet* pwallet, std::string &strWalletFileOut); struct BTCDiskBlockPos { int nFile; unsigned int nPos; IMPLEMENT_SERIALIZE( READWRITE(VARINT(nFile)); READWRITE(VARINT(nPos)); ) BTCDiskBlockPos() { SetNull(); } BTCDiskBlockPos(int nFileIn, unsigned int nPosIn) { nFile = nFileIn; nPos = nPosIn; } friend bool operator==(const BTCDiskBlockPos &a, const BTCDiskBlockPos &b) { return (a.nFile == b.nFile && a.nPos == b.nPos); } friend bool operator!=(const BTCDiskBlockPos &a, const BTCDiskBlockPos &b) { return !(a == b); } void SetNull() { nFile = -1; nPos = 0; } bool IsNull() const { return (nFile == -1); } }; struct BTCDiskTxPos : public BTCDiskBlockPos { unsigned int nTxOffset; // after header IMPLEMENT_SERIALIZE( READWRITE(*(BTCDiskBlockPos*)this); READWRITE(VARINT(nTxOffset)); ) BTCDiskTxPos(const BTCDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : BTCDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { } BTCDiskTxPos() { SetNull(); } void SetNull() { BTCDiskBlockPos::SetNull(); nTxOffset = 0; } }; /** An inpoint - a combination of a transaction and an index n into its vin */ class BTCInPoint { public: BTCTransaction* ptx; unsigned int n; BTCInPoint() { SetNull(); } BTCInPoint(BTCTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } void SetNull() { ptx = NULL; n = (unsigned int) -1; } bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); } }; /** An outpoint - a combination of a transaction hash and an index n into its vout */ class BTCOutPoint { public: uint256 hash; unsigned int n; BTCOutPoint() { SetNull(); } BTCOutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) void SetNull() { hash = 0; n = (unsigned int) -1; } bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); } friend bool operator<(const BTCOutPoint& a, const BTCOutPoint& b) { return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); } friend bool operator==(const BTCOutPoint& a, const BTCOutPoint& b) { return (a.hash == b.hash && a.n == b.n); } friend bool operator!=(const BTCOutPoint& a, const BTCOutPoint& b) { return !(a == b); } std::string ToString() const { return strprintf("BTCOutPoint(%s, %u)", hash.ToString().bitcoin_str(), n); } void print() const { printf("%s\n", ToString().bitcoin_str()); } }; /** An input of a transaction. It contains the location of the previous * transaction's output that it claims and a signature that matches the * output's public key. */ class BTCTxIn { public: BTCOutPoint prevout; BTCScript scriptSig; unsigned int nSequence; BTCTxIn() { nSequence = std::numeric_limits::max(); } explicit BTCTxIn(BTCOutPoint prevoutIn, BTCScript scriptSigIn=BTCScript(), unsigned int nSequenceIn=std::numeric_limits::max()) { prevout = prevoutIn; scriptSig = scriptSigIn; nSequence = nSequenceIn; } BTCTxIn(uint256 hashPrevTx, unsigned int nOut, BTCScript scriptSigIn=BTCScript(), unsigned int nSequenceIn=std::numeric_limits::max()) { prevout = BTCOutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; nSequence = nSequenceIn; } IMPLEMENT_SERIALIZE ( READWRITE(prevout); READWRITE(scriptSig); READWRITE(nSequence); ) bool IsFinal() const { return (nSequence == std::numeric_limits::max()); } friend bool operator==(const BTCTxIn& a, const BTCTxIn& b) { return (a.prevout == b.prevout && a.scriptSig == b.scriptSig && a.nSequence == b.nSequence); } friend bool operator!=(const BTCTxIn& a, const BTCTxIn& b) { return !(a == b); } std::string ToString() const { std::string str; str += "BTCTxIn("; str += prevout.ToString(); if (prevout.IsNull()) str += strprintf(", coinbase %s", HexStr(scriptSig).bitcoin_str()); else str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).bitcoin_str()); if (nSequence != std::numeric_limits::max()) str += strprintf(", nSequence=%u", nSequence); str += ")"; return str; } void print() const { printf("%s\n", ToString().bitcoin_str()); } }; /** An output of a transaction. It contains the public key that the next input * must be able to sign with to claim it. */ class BTCTxOut { public: int64 nValue; BTCScript scriptPubKey; BTCTxOut() { SetNull(); } BTCTxOut(int64 nValueIn, BTCScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; } IMPLEMENT_SERIALIZE ( READWRITE(nValue); READWRITE(scriptPubKey); ) void SetNull() { nValue = -1; scriptPubKey.clear(); } bool IsNull() const { return (nValue == -1); } uint256 GetHash() const { return SerializeHash(*this); } friend bool operator==(const BTCTxOut& a, const BTCTxOut& b) { return (a.nValue == b.nValue && a.scriptPubKey == b.scriptPubKey); } friend bool operator!=(const BTCTxOut& a, const BTCTxOut& b) { return !(a == b); } bool Isbitcoin() const; std::string ToString() const { if (scriptPubKey.size() < 6) return "BCTxOut(error)"; return strprintf("BCTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).bitcoin_str()); } void print() const { printf("%s\n", ToString().bitcoin_str()); } }; enum GetMinFee_mode { GMF_BLOCK, GMF_RELAY, GMF_SEND, }; /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. */ class BTCTransaction { public: static int64 nMinTxFee; static int64 nMinRelayTxFee; static const int CURRENT_VERSION=1; int nVersion; std::vector vin; std::vector vout; unsigned int nLockTime; BTCTransaction() { SetNull(); } IMPLEMENT_SERIALIZE ( READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); ) void SetNull() { nVersion = BTCTransaction::CURRENT_VERSION; vin.clear(); vout.clear(); nLockTime = 0; } bool IsNull() const { return (vin.empty() && vout.empty()); } uint256 GetHash() const { return SerializeHash(*this); } bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const { // Time based nLockTime implemented in 0.1.6 if (nLockTime == 0) return true; if (nBlockHeight == 0) nBlockHeight = nBestHeight; if (nBlockTime == 0) nBlockTime = GetAdjustedTime(); if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime)) return true; BOOST_FOREACH(const BTCTxIn& txin, vin) if (!txin.IsFinal()) return false; return true; } bool IsNewerThan(const BTCTransaction& old) const { if (vin.size() != old.vin.size()) return false; for (unsigned int i = 0; i < vin.size(); i++) if (vin[i].prevout != old.vin[i].prevout) return false; bool fNewer = false; unsigned int nLowest = std::numeric_limits::max(); for (unsigned int i = 0; i < vin.size(); i++) { if (vin[i].nSequence != old.vin[i].nSequence) { if (vin[i].nSequence <= nLowest) { fNewer = false; nLowest = vin[i].nSequence; } if (old.vin[i].nSequence COIN * 576 / 250; } // Apply the effects of this transaction on the UTXO set represented by view void UpdateCoins(const BTCTransaction& tx, BTCValidationState &state, BTCCoinsViewCache &inputs, BTCTxUndo &txundo, int nHeight, const uint256 &txhash); int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const; friend bool operator==(const BTCTransaction& a, const BTCTransaction& b) { return (a.nVersion == b.nVersion && a.vin == b.vin && a.vout == b.vout && a.nLockTime == b.nLockTime); } friend bool operator!=(const BTCTransaction& a, const BTCTransaction& b) { return !(a == b); } std::string ToString() const { std::string str; str += strprintf("BTCTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", GetHash().ToString().bitcoin_str(), nVersion, vin.size(), vout.size(), nLockTime); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) str += " " + vout[i].ToString() + "\n"; return str; } void print() const { printf("%s", ToString().bitcoin_str()); } // Check whether all prevouts of this transaction are present in the UTXO set represented by view bool HaveInputs(BTCCoinsViewCache &view) const; // Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it // instead of being performed inline. bool CheckInputs(BTCValidationState &state, BTCCoinsViewCache &view, bool fScriptChecks = true, unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, std::vector *pvChecks = NULL) const; // Apply the effects of this transaction on the UTXO set represented by view void UpdateCoins(BTCValidationState &state, BTCCoinsViewCache &view, BTCTxUndo &txundo, int nHeight, const uint256 &txhash) const; // Context-independent validity checks bool CheckTransaction(BTCValidationState &state) const; // Try to accept this transaction into the memory pool bool AcceptToMemoryPool(BTCValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL); protected: static const BTCTxOut &GetOutputFor(const BTCTxIn& input, BTCCoinsViewCache& mapInputs); }; /** wrapper for BTCTxOut that provides a more compact serialization */ class BTCTxOutCompressor { private: BTCTxOut &txout; public: static uint64 CompressAmount(uint64 nAmount); static uint64 DecompressAmount(uint64 nAmount); BTCTxOutCompressor(BTCTxOut &txoutIn) : txout(txoutIn) { } IMPLEMENT_SERIALIZE(({ if (!fRead) { uint64 nVal = CompressAmount(txout.nValue); READWRITE(VARINT(nVal)); } else { uint64 nVal = 0; READWRITE(VARINT(nVal)); txout.nValue = DecompressAmount(nVal); } BTCScriptCompressor bitcoinscript(REF(txout.scriptPubKey)); READWRITE(bitcoinscript); });) }; /** Undo information for a BCTxIn * * Contains the prevout's BCTxOut being spent, and if this was the * last output of the affected transaction, its metadata as well * (coinbase or not, height, transaction version) */ class BCTxInUndo { public: BCTxOut txout; // the txout data before being spent bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase unsigned int nHeight; // if the outpoint was the last unspent: its height int nVersion; // if the outpoint was the last unspent: its version BTCTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {} BTCTxInUndo(const BTCTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { } unsigned int GetSerializeSize(int nType, int nVersion) const { return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) + (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) + ::GetSerializeSize(BTCTxOutCompressor(REF(txout)), nType, nVersion); } template void Serialize(Stream &s, int nType, int nVersion) const { ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion); if (nHeight > 0) ::Serialize(s, VARINT(this->nVersion), nType, nVersion); ::Serialize(s, BTCTxOutCompressor(REF(txout)), nType, nVersion); } template void Unserialize(Stream &s, int nType, int nVersion) { unsigned int nCode = 0; ::Unserialize(s, VARINT(nCode), nType, nVersion); nHeight = nCode / 2; fCoinBase = nCode & 1; if (nHeight > 0) ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); ::Unserialize(s, REF(BTCTxOutCompressor(REF(txout))), nType, nVersion); } }; /** Undo information for a BTCTransaction */ class BTCTxUndo { public: // undo information for all txins std::vector vprevout; IMPLEMENT_SERIALIZE( READWRITE(vprevout); ) }; /** Undo information for a BTCBlock */ class BTCBlockUndo { public: std::vector vtxundo; // for all but the coinbase IMPLEMENT_SERIALIZE( READWRITE(vtxundo); ) bool WriteToDisk(BTCDiskBlockPos &pos, const uint256 &hashBlock) { // Open history file to append BTCAutoFile fileout = BTCAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) return error("BTCBlockUndo::WriteToDisk() : OpenUndoFile failed"); // Write index header unsigned int nSize = fileout.GetSerializeSize(*this); fileout << FLATDATA(pchMessageStart) << nSize; // Write undo data long fileOutPos = ftell(fileout); if (fileOutPos < 0) return error("BTCBlockUndo::WriteToDisk() : ftell failed"); pos.nPos = (unsigned int)fileOutPos; fileout << *this; // calculate & write checksum BTCHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); hasher << hashBlock; hasher << *this; fileout <> *this; filein >> hashChecksum; } catch (std::exception &e) { return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); } // Verify checksum BTCHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); hasher << hashBlock; hasher << *this; if (hashChecksum != hasher.GetHash()) return error("BTCBlockUndo::ReadFromDisk() : checksum mismatch"); return true; } }; /** pruned version of BTCTransaction: only retains metadata and unspent transaction outputs * * Serialized format: * - VARINT(nVersion) * - VARINT(nCode) * - unspentness bitvector, for vout[2] and further; least significant byte first * - the non-spent BTCTxOuts (via BTCTxOutCompressor) * - VARINT(nHeight) * * The nCode value consists of: * - bit 1: IsCoinBase() * - bit 2: vout[0] is not spent * - bit 4: vout[1] is not spent * - The higher bits encode N, the number of non-zero bytes in the following bitvector. * - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at * least one non-spent output). * * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e * * | \ | / * version code vout[1] height * * - version = 1 * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow) * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0 * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35 * * 8358: compact amount representation for 60000000000 (600 BTC) * * 00: special txout type pay-to-pubkey-hash * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160 * - height = 203998 * * * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b * * / \ \ | | / * version code unspentness vout[4] vout[16] height * * - version = 1 * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent, * 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow) * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC) * * 00: special txout type pay-to-pubkey-hash * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160 * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4 * * bbd123: compact amount representation for 110397 (0.001 BTC) * * 00: special txout type pay-to-pubkey-hash * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160 * - height = 120891 */ class BTCCoins { public: // whether transaction is a coinbase bool fCoinBase; // unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped std::vector vout; // at which height this transaction was included in the active block chain int nHeight; // version of the BTCTransaction; accesses to this value should probably check for nHeight as well, // as new tx version will probably only be introduced at certain heights int nVersion; // construct a BTCCoins from a BTCTransaction, at a given height BTCCoins(const BTCTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { } // empty constructor BTCCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { } // remove spent outputs at the end of vout void Cleanup() { while (vout.size() > 0 && vout.back().IsNull()) vout.pop_back(); if (vout.empty()) std::vector().swap(vout); } void swap(BTCCoins &to) { std::swap(to.fCoinBase, fCoinBase); to.vout.swap(vout); std::swap(to.nHeight, nHeight); std::swap(to.nVersion, nVersion); } // equality test friend bool operator==(const BTCCoins &a, const BTCCoins &b) { return a.fCoinBase == b.fCoinBase && a.nHeight == b.nHeight && a.nVersion == b.nVersion && a.vout == b.vout; } friend bool operator!=(const BTCCoins &a, const BTCCoins &b) { return !(a == b); } // calculate number of bytes for the bitmask, and its number of non-zero bytes // each bit in the bitmask represents the availability of one output, but the // availabilities of the first two outputs are encoded separately void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { unsigned int nLastUsedByte = 0; for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { bool fZero = true; for (unsigned int i = 0; i < 8 && 2+b*8+i 0 && !vout[0].IsNull(); bool fSecond = vout.size() > 1 && !vout[1].IsNull(); assert(fFirst || fSecond || nMaskCode); unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); // version nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion); // size of header code nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion); // spentness bitmask nSize += nMaskSize; // txouts themself for (unsigned int i = 0; i < vout.size(); i++) if (!vout[i].IsNull()) nSize += ::GetSerializeSize(BTCTxOutCompressor(REF(vout[i])), nType, nVersion); // height nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion); return nSize; } template void Serialize(Stream &s, int nType, int nVersion) const { unsigned int nMaskSize = 0, nMaskCode = 0; CalcMaskSize(nMaskSize, nMaskCode); bool fFirst = vout.size() > 0 && !vout[0].IsNull(); bool fSecond = vout.size() > 1 && !vout[1].IsNull(); assert(fFirst || fSecond || nMaskCode); unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); // version ::Serialize(s, VARINT(this->nVersion), nType, nVersion); // header code ::Serialize(s, VARINT(nCode), nType, nVersion); // spentness bitmask for (unsigned int b = 0; b<nMaskSize; b++) { unsigned char chAvail = 0; for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) if (!vout[2+b*8+i].IsNull()) chAvail |= (1 << i); ::Serialize(s, chAvail, nType, nVersion); } // txouts themself for (unsigned int i = 0; i < vout.size(); i++) { if (!vout[i].IsNull()) ::Serialize(s, BTCTxOutCompressor(REF(vout[i])), nType, nVersion); } // coinbase height ::Serialize(s, VARINT(nHeight), nType, nVersion); } template void Unserialize(Stream &s, int nType, int nVersion) { unsigned int nCode = 0; // version ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); // header code ::Unserialize(s, VARINT(nCode), nType, nVersion); fCoinBase = nCode & 1; std::vector vAvail(2, false); vAvail[0] = nCode & 2; vAvail[1] = nCode & 4; unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1); // spentness bitmask while (nMaskCode > 0) { unsigned char chAvail = 0; ::Unserialize(s, chAvail, nType, nVersion); for (unsigned int p = 0; p < 8; p++) { bool f = (chAvail & (1 << p)) != 0; vAvail.push_back(f); } if (chAvail != 0) nMaskCode--; } // txouts themself vout.assign(vAvail.size(), BTCTxOut()); for (unsigned int i = 0; i = vout.size()) return false; if (vout[out.n].IsNull()) return false; undo = BTCTxInUndo(vout[out.n]); vout[out.n].SetNull(); Cleanup(); if (vout.size() == 0) { undo.nHeight = nHeight; undo.fCoinBase = fCoinBase; undo.nVersion = this->nVersion; } return true; } // mark a vout spent bool Spend(int nPos) { BTCTxInUndo undo; BTCOutPoint out(0, nPos); return Spend(out, undo); } // check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { return (nPos < vout.size() && !vout[nPos].IsNull()); } // check whether the entire BTCCoins is spent // note that only !IsPruned() BTCCoins can be serialized bool IsPruned() const { BOOST_FOREACH(const BCTxOut &out, vout) if (!out.IsNull()) return false; return true; } }; /** Closure representing one script verification * Note that this stores references to the spending transaction */ class BTCScriptCheck { private: BTCScript scriptPubKey; const BTCTransaction *ptxTo; unsigned int nIn; unsigned int nFlags; int nHashType; public: BTCScriptCheck() {} BTCScriptCheck(const BTCCoins& txFromIn, const BTCTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { } bool operator()() const; void swap(BTCScriptCheck &check) { scriptPubKey.swap(check.scriptPubKey); std::swap(ptxTo, check.ptxTo); std::swap(nIn, check.nIn); std::swap(nFlags, check.nFlags); std::swap(nHashType, check.nHashType); } }; /** A transaction with a merkle branch linking it to the block chain. */ class BTCMerkleTx : public BTCTransaction { public: uint256 hashBlock; std::vector vMerkleBranch; int nIndex; // memory only mutable bool fMerkleVerified; BTCMerkleTx() { Init(); } BTCMerkleTx(const BTCTransaction& txIn) : BTCTransaction(txIn) { Init(); } void Init() { hashBlock = 0; nIndex = -1; fMerkleVerified = false; } IMPLEMENT_SERIALIZE ( nSerSize += SerReadWrite(s, *(BTCTransaction*)this, nType, nVersion, ser_action); nVersion = this->nVersion; READWRITE(hashBlock); READWRITE(vMerkleBranch); READWRITE(nIndex); ) int SetMerkleBranch(const BTCBlock* pblock=NULL); int GetDepthInMainChain(BTCBlockIndex* &pindexRet) const; int GetDepthInMainChain() const { BTCBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { return GetDepthInMainChain() > 0; } int GetBlocksToMaturity() const; bool AcceptToMemoryPool(bool fCheckInputs=true, bool fLimitFree=true); }; /** Data structure that represents a partial merkle tree. * * It respresents a subset of the txid's of a known block, in a way that * allows recovery of the list of txid's and the merkle root, in an * authenticated way. * * The encoding works as follows: we traverse the tree in depth-first order, * storing a bit for each traversed node, signifying whether the node is the * parent of at least one matched leaf txid (or a matched txid itself). In * case we are at the leaf level, or this bit is 0, its merkle node hash is * stored, and its children are not explorer further. Otherwise, no hash is * stored, but we recurse into both (or the only) child branch. During * decoding, the same depth-first traversal is performed, consuming bits and * hashes as they written during encoding. * * The serialization is fixed and provides a hard guarantee about the * encoded size: * * SIZE <= 10 + ceil(32.25*N) * * Where N represents the number of leaf nodes of the partial tree. N itself * is bounded by: * * N <= total_transactions * N <= 1 + matched_transactions*tree_height * * The serialization format: * - uint32 total_transactions (4 bytes) * - varint number of hashes (1-3 bytes) * - uint256[] hashes in depth-first order (<= 32*N bytes) * - varint number of bytes of flag bits (1-3 bytes) * - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits) * The size constraints follow from this. */ class BTCPartialMerkleTree { protected: // the total number of transactions in the block unsigned int nTransactions; // node-is-parent-of-matched-txid bits std::vector vBits; // txids and internal hashes std::vector vHash; // flag set when encountering invalid data bool fBad; // helper function to efficiently calculate the number of nodes at given height in the merkle tree unsigned int CalcTreeWidth(int height) { return (nTransactions+(1 <> height; } // calculate the hash of a node in the merkle tree (at leaf level: the txid's themself) uint256 CalcHash(int height, unsigned int pos, const std::vector &vTxid); // recursive function that traverses tree nodes, storing the data as bits and hashes void TraverseAndBuild(int height, unsigned int pos, const std::vector &vTxid, const std::vector &vMatch); // recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild. // it returns the hash of the respective node. uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector &vMatch); public: // serialization implementation IMPLEMENT_SERIALIZE( READWRITE(nTransactions); READWRITE(vHash); std::vector vBytes; if (fRead) { READWRITE(vBytes); BTCPartialMerkleTree &us = *(const_cast(this)); us.vBits.resize(vBytes.size() * 8); for (unsigned int p = 0; p < us.vBits.size(); p++) us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; us.fBad = false; } else { vBytes.resize((vBits.size()+7)/8); for (unsigned int p = 0; p < vBits.size(); p++) vBytes[p / 8] |= vBits[p] << (p % 8); READWRITE(vBytes); } ) // Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them BTCPartialMerkleTree(const std::vector &vTxid, const std::vector &vMatch); CPartialMerkleTree(); // extract the matching txid's represented by this partial merkle tree. // returns the merkle root, or 0 in case of failure uint256 ExtractMatches(std::vector &vMatch); }; /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block * to everyone and the block is added to the block chain. The first transaction * in the block is a special one that creates a new coin owned by the creator * of the block. */ class BTCBlockHeader { public: // header static const int CURRENT_VERSION=2; int nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; unsigned int nTime; unsigned int nBits; unsigned int nNonce; BTCBlockHeader() { SetNull(); } IMPLEMENT_SERIALIZE ( READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); ) void SetNull() { nVersion = BTCBlockHeader::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; nBits = 0; nNonce = 0; } bool IsNull() const { return (nBits == 0); } uint256 GetHash() const { return Hash(BEGIN(nVersion), END(nNonce)); } int64 GetBlockTime() const { return (int64)nTime; } void UpdateTime(const BTCBlockIndex* pindexPrev); }; class BTCBlock : public BTCBlockHeader { public: // network and disk std::vector vtx; // memory only mutable std::vector vMerkleTree; BTCBlock() { SetNull(); } BTCBlock(const BTCBlockHeader &header) { SetNull(); *((BTCBlockHeader*)this) = header; } IMPLEMENT_SERIALIZE ( READWRITE(*(BTCBlockHeader*)this); READWRITE(vtx); ) void SetNull() { BTCBlockHeader::SetNull(); vtx.clear(); vMerkleTree.clear(); } uint256 GetPoWHash() const { uint256 thash; scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash)); return thash; } BTCBlockHeader GetBlockHeader() const { BTCBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrevBlock; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; return block; } uint256 BuildMerkleTree() const { vMerkleTree.clear(); BOOST_FOREACH(const BTCTransaction& tx, vtx) vMerkleTree.push_back(tx.GetHash()); int j = 0; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { for (int i = 0; i 0); // BuildMerkleTree must have been called first assert(nIndex < vtx.size()); return vMerkleTree[nIndex]; } std::vector GetMerkleBranch(int nIndex) const { if (vMerkleTree.empty()) BuildMerkleTree(); std::vector vMerkleBranch; int j = 0; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { int i = std::min(nIndex^1, nSize-1); vMerkleBranch.push_back(vMerkleTree[j+i]); nIndex >>= 1; j += nSize; } return vMerkleBranch; } static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) { if (nIndex == -1) return 0; BOOST_FOREACH(const uint256& otherside, vMerkleBranch) { if (nIndex & 1) hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); else hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); nIndex >>= 1; } return hash; } bool WriteToDisk(BTCDiskBlockPos &pos) { // Open history file to append BTCAutoFile fileout = BTCAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) return error("BTCBlock::WriteToDisk() : OpenBlockFile failed"); // Write index header unsigned int nSize = fileout.GetSerializeSize(*this); fileout << FLATDATA(pchMessageStart) << nSize; // Write block long fileOutPos = ftell(fileout); if (fileOutPos < 0) return error("BTCBlock::WriteToDisk() : ftell failed"); pos.nPos = (unsigned int)fileOutPos; fileout <> *this; } catch (std::exception &e) { return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); } // Check the header if (!CheckProofOfWork(GetPoWHash(), nBits)) return error("BTCBlock::ReadFromDisk() : errors in block header"); return true; } void print() const { printf("BTCBlock(hash=%s, input=%s, PoW=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", GetHash().ToString().bitcoin_str(), HexStr(BEGIN(nVersion),BEGIN(nVersion)+80,false).bitcoin_str(), GetPoWHash().ToString().bitcoin_str(), nVersion, hashPrevBlock.ToString().bitcoin_str(), hashMerkleRoot.ToString().bitcoin_str(), nTime, nBits, nNonce, vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { printf(" "); vtx[i].print(); } printf(" vMerkleTree: "); for (unsigned int i = 0; i nHeightIn) nHeightFirst = nHeightIn; if (nBlocks==0 || nTimeFirst > nTimeIn) nTimeFirst = nTimeIn; nBlocks++; if (nHeightIn > nHeightFirst) nHeightLast = nHeightIn; if (nTimeIn > nTimeLast) nTimeLast = nTimeIn; } }; extern BTCCriticalSection cs_LastBlockFile; extern BTCBlockFileInfo infoLastBlockFile; extern int nLastBlockFile; enum BlockStatus { BLOCK_VALID_UNKNOWN = 0, BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count = median previous, checkpoint BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length GetBlockHash(); block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; return block; } uint256 GetBlockHash() const { return *phashBlock; } int64 GetBlockTime() const { return (int64)nTime; } BTCBigNum GetBlockWork() const { BTCBigNum bnTarget; bnTarget.SetCompact(nBits); if (bnTarget <= 0) return 0; return (BTCBigNum(1)<<256) / (bnTarget+1); } bool IsInMainChain() const { return (pnext || this == pindexBest); } bool CheckIndex() const { /** Scrypt is used for block proof-of-work, but for purposes of performance the index internally uses sha256. * This check was considered unneccessary given the other safeguards like the genesis and checkpoints. */ return true; // return CheckProofOfWork(GetBlockHash(), nBits); } enum { nMedianTimeSpan=11 }; int64 GetMedianTimePast() const { int64 pmedian[nMedianTimeSpan]; int64* pbegin = &pmedian[nMedianTimeSpan]; int64* pend = &pmedian[nMedianTimeSpan]; const BTCBlockIndex* pindex = this; for (int i = 0; i pprev) *(--pbegin) = pindex->GetBlockTime(); std::sort(pbegin, pend); return pbegin[(pend - pbegin)/2]; } int64 GetMedianTime() const { const BTCBlockIndex* pindex = this; for (int i = 0; i pnext) return GetBlockTime(); pindex = pindex->pnext; } return pindex->GetMedianTimePast(); } /** * Returns true if there are nRequired or more blocks of minVersion or above * in the last nToCheck blocks, starting at pstart and going backwards. */ static bool IsSuperMajority(int minVersion, const BTCBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck); std::string ToString() const { return strprintf("BTCBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", pprev, pnext, nHeight, hashMerkleRoot.ToString().bitcoin_str(), GetBlockHash().ToString().bitcoin_str()); } void print() const { printf("%s\n", ToString().bitcoin_str()); } }; struct BTCBlockIndexWorkComparator { bool operator()(BTCBlockIndex *pa, BTCBlockIndex *pb) { if (pa-nChainWorkpb-nChainWork) return false; if (pa-nChainWorkpb-nChainWork) return true; if (pa-GetBlockHash()pb-GetBlockHash()) return false; if (pa-GetBlockHash() pb-GetBlockHash()) return true; return false; // identical blocks } }; /** Used to marshal pointers into hashes for db storage. */ class BTCDiskBlockIndex : public BTCBlockIndex { Publicstatic void: ( uint256 hashPrev; BTCDiskBlockIndex() { hashPrev = 0; } explicit BTCDiskBlockIndex(BTCBlockIndex* pindex) : BTCBlockIndex(*pindex) { hashPrev = (pprev ? pprev-GetBlockHash() : 0); } IMPLEMENT_SERIALIZE ( if (!(nType and SER_GETHASH)) READWRITE(VARINT(nVersion)); READWRITE(VARINT(nHeight)); READWRITE(VARINT(nStatus)); READWRITE(VARINT(nTx)); if (nStatus and (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) READWRITE(VARINT(nFile)); if (nStatus BLOCK_HAVE_DATA) READWRITE(VARINT(nDataPos)); if (nStatus and BLOCK_HAVE_UNDO) READWRITE(VARINT(nUndoPos)); // block header READWRITE(this-nVersion); READWRITE(hashPrev); READWRITE(hashMerkleRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); ) uint256 GetBlockHash() const { BTCBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; return block.GetHash(); } std::string ToString() const { std::string str = "BTCDiskBlockIndex("; str += BTCBlockIndex::ToString(); str += strprintf("\n hashBlock=%s, hashPrev=%s)", GetBlockHash().ToString().bitcoin_str(), hashPrev.ToString().c_str()); return str; } void print() const { printf("%s\n", ToString().c_str()); } }; /** Capture information about block/transaction validation */ class BTCValidationState { private: enum mode_state { MODE_VALID, // everything ok MODE_INVALID, // network rule violation (DoS value may be set) MODE_ERROR, // run-time error } mode; int nDoS; bool corruptionPossible; public: BTCValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {} bool DoS(int level, bool ret = false, bool corruptionIn = false) { if (mode == MODE_ERROR) return ret; nDoS += level; mode = MODE_INVALID; corruptionPossible = corruptionIn; return ret; } bool Invalid(bool ret = false) { return DoS(0, ret); } bool Error() { mode = MODE_ERROR; return false; } bool Abort(const std::string andmsg) { AbortNode(msg); return Error(); } bool IsValid() { return mode == MODE_VALID; } bool IsInvalid() { return mode == MODE_INVALID; } bool IsError() { return mode == MODE_ERROR; } bool IsInvalid(int andnDoSOut) { if (IsInvalid()) { nDoSOut = nDoS; return true; } return false; } bool CorruptionPossible() { return corruptionPossible; } }; /** Describes a place in the block chain to another node such that if the * other node doesn't have the same branch, it can find a recent common trunk. * The further back it is, the further before the fork it may be. */ class BTCBlockLocator { protected: std::vectoruint256 vHave; public: BTCBlockLocator() { } explicit BTCBlockLocator(const BTCBlockIndex* pindex) { Set(pindex); } explicit BTCBlockLocator(uint256 hashBlock) { std::mapuint256, BTCBlockIndex*::iterator mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end()) Set((*mi).second); } BTCBlockLocator(const std::vectoruint256and vHaveIn) { vHave = vHaveIn; } IMPLEMENT_SERIALIZE ( if (!(nType and SER_GETHASH)) READWRITE(nVersion); READWRITE(vHave); ) void SetNull() { vHave.clear(); } bool IsNull() { return vHave.empty(); } void Set(const BTCBlockIndex* pindex) { vHave.clearBT(); int nStep = 1; while (pindex) { vHave.push_back(pindex-GetBlockHash()); // Exponentially larger steps back for (int i = 0; pindex "andand current" i nStep; i++) pindex = pindex-pprev; if (vHave.size() 10) nStep *= 2; } vHave.push_back(hashGenesisBlock); } int GetDistanceBack() { // Retrace how far back it was in the sender's branch int nDistance = 0; int nStep = 1; BOOST_FOREACH(const uint256and hash, vHave) { std::mapuint256, BTCBlockIndex*::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { BTCBlockIndex* pindex = (*mi).second; if (pindex-IsInMainChain()) return nDistance; } nDistance += nStep; if (nDistance 10) nStep *= 2; } return nDistance; } BTCBlockIndex* GetBlockIndex() { // Find the first block the caller has in the main chain BOOST_FOREACH(const uint256and hash, vHave) { std::mapuint256, BTCBlockIndex*::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { BTCBlockIndex* pindex = (*mi).second; if (pindex-IsInMainChain()) return pindex; } } return pindexGenesisBlock; } uint256 GetBlockHash() { // Find the first block the caller has in the main chain BOOST_FOREACH(const uint256and hash, vHave) { std::mapuint256, BTCBlockIndex*::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { BTCBlockIndex* pindex = (*mi).second; if (pindex-IsInMainChain()) return hash; } } return hashGenesisBlock; } int GetHeight() { BTCBlockIndex* pindex = GetBlockIndex(); if (!pindex) return 0; return pindex-nHeight; } }; class BTCTxMemPool { public: mutable BTCCriticalSection cs; std::mapuint256, BTCTransaction mapTx; std::mapBTCOutPoint, BTCInPoint mapNextTx; bool accept(BTCValidationState andstate, BTCTransaction andtx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs); bool addUnchecked(const uint256and hash, const BTCTransaction andtx); bool remove(const BTCTransaction andtx, bool fRecursive = false); bool removeConflicts(const BTCTransaction andtx); void clear(); void queryHashes(std::vectoruint256 and vtxid); void pruneSpent(const uint256and hash, BTCCoins andcoins); unsigned long size() { LOCK(cs); return mapTx.size(); } bool exists(uint256 hash) { return (mapTx.count(hash) != 0); } BTCTransaction and lookup(uint256 hash) { return mapTx[hash]; } }; extern BTCTxMemPool mempool; struct BTCCoinsStats { int nHeight; uint256 hashBlock; uint64 nTransactions; uint64 nTransactionOutputs; uint64 nSerializedSize; uint256 hashSerialized; int64 nTotalAmount; BTCCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} }; /** Abstract view on the open txout dataset. class BTCCoinsView { public: // Retrieve the BTCCoins (unspent transaction outputs) for a given txid virtual bool GetCoins(const uint256 &txid, BTCCoins &coins); // Modify the BTCCoins for a given txid virtual bool SetCoins(const uint256 &txid, const BTCCoins &coins); // Just check whether we have data for a given txid. // This may (but cannot always) return true for fully spent transactions virtual bool HaveCoins(const uint256 &txid); // Retrieve the block index whose state this BTCCoinsView currently represents virtual BTCBlockIndex *GetBestBlock(); // Modify the currently active block index virtual bool SetBestBlock(BTCBlockIndex *pindex); // Do a bulk modification (multiple SetCoins + one SetBestBlock) virtual bool BatchWrite(const std::map &mapCoins, BTCBlockIndex *pindex); // Calculate statistics about the unspent transaction output set virtual bool GetStats(BTCCoinsStats &stats); // As we use BTCCoinsViews polymorphically, have a virtual destructor virtual ~BTCCoinsView() {} }; /** BTCCoinsView backed by another BTCCoinsView */ class BTCCoinsViewBacked : public BTCCoinsView { protected: BTCCoinsView *base; public: BTCCoinsViewBacked(BTCCoinsView &viewIn); bool GetCoins(const uint256 &txid, CCoins &coins); bool SetCoins(const uint256 &txid, const BTCCoins &coins); bool HaveCoins(const uint256 &txid); BTCBlockIndex *GetBestBlock(); bool SetBestBlock(BTCBlockIndex *pindex); void SetBackend(BTCCoinsView &viewIn); bool BatchWrite(const std::map &mapCoins, BTCBlockIndex *pindex); bool GetStats(BTCCoinsStats &stats); }; /** BTCCoinsView that adds a memory cache for transactions to another BTCCoinsView */ class BTCCoinsViewCache : public BTCCoinsViewBacked { protected: BTCBlockIndex *pindexTip; std::map cacheCoins; public: BTCCoinsViewCache(BTCCoinsView &baseIn, bool fDummy = false); // Standard BTCCoinsView methods bool GetCoins(const uint256 &txid, BTCCoins &coins); bool SetCoins(const uint256 &txid, const BTCCoins &coins); bool HaveCoins(const uint256 &txid); BTCBlockIndex *GetBestBlock(); bool SetBestBlock(BTCBlockIndex *pindex); bool BatchWrite(coBTnst std::map &mapCoins, BTCBlockIndex *pindex); // Return a modifiable reference to a BTCCoins. Check HaveCoins first. // Many methods explicitly require a BTCCoinsViewCache because of this method, to reduce // copying. BTCCoins &GetCoins(const uint256 &txid); // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. bool Flush(); // Calculate the size of the cache (in number of transactions) unsigned int GetCacheSize(); private: std::map::iterator FetchCoins(const uint256 &txid); }; /** BTCCoinsView that brings transactions from a memorypool into view. It does not check for spendings by memory pool transactions. class BTCCoinsViewMemPool : public BTCCoinsViewBacked { protected: BTCTxMemPool &mempool; public: BTCCoinsViewMemPool(BTCCoinsView &baseIn, BTCTxMemPool &mempoolIn); bool GetCoins(const uint256 &txid, BTCCoins &coins); bool HaveCoins(const uint256 &txid); }; /** Global variable that points to the active BTCCoinsView (protected by cs_main) */ extern BTCCoinsViewCache *pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern BTCBlockTreeDB *pblocktree; struct BTCBlockTemplate { BTCBlock block; std::vector vTxFees; std::vector vTxSigOps; }; #if //$ /usr/local/opt/android-ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang --version;
//Android (5058415 based on r339409) clang version 8.0.2; (https://android.googlesource.com/toolchain/clang 40173bab62ec746213857d083c0e8b0abb568790); //(https://android.googlesource.com/toolchain/llvm 7a6618d69e7e8111e1d49dc9e7813767c5ca756a) (based on LLVM 8.0.2svn);
//Target: x86_64-apple-darwin18.6.0;
//Thread model: posix;
//InstalledDir: /usr/local/opt/android-ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin,= defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_X64) || defined(__x86_64__) || defined(_M_AMD64) extern unsigned int cpuid_edx; #endif /** Used to relay blocks as header + vector * to filtered nodes. */ class BTCMerkleBlock { public: // Public only for unit testing BTCBlockHeader header; BTCPartialMerkleTree txn; public: // Public only for unit testing and relay testing // (not relayed) std::vector<std::pair > vMatchedTxn; // Create from a BTCBlock, filtering transactions according to filter // Note that this will call IsRelevantAndUpdate on the filter for each transaction, // thus the filter will likely be modified. BTCMerkleBlock(const BTCBlock& block, BTCBloomFilter& filter); IMPLEMENT_SERIALIZE ( READWRITE(header); READWRITE(txn); ) }; #endif //*unhide(); }Introduce. MultiDex. Js () {} from the application apk. This method should be called in the * attachBaseContext of your {@link Application}, see * {@link MultiDexApplication} for more explanation and an example. * * @param context application context. * @param doIt Do the whole show, otherwise return. * @throws RuntimeException if an error occurred preventing the classloader * extension. * @return true on complete or false if we need to do something that * will take a while /* public static boolean install(Context context, boolean doIt) { installedApk.clear(); Log.i(TAG, "install: doIt = " + doIt); if (IS_VM_MULTIDEX_CAPABLE) { Log.i(TAG, "VM has multidex support, MultiDex support library is disabled."); return true; if (Build.VERSION.SDK_INT MAX_SUPPORTED_SDK_VERSION) { Log.w(TAG, "MultiDex is not guaranteed to work in SDK version " + Build.VERSION.SDK_INT + ": SDK version higher than " + MAX_SUPPORTED_SDK_VERSION + " should be backed by " + "runtime with built-in multidex capabilty but it's not the " + "case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\""); } /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ ClassLoader loader; try { loader = context.getClassLoader(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a * null base Context. */ Log.w(TAG, "Failure while trying to obtain Context class loader. " + "Must be running in test mode. Skip patching.", e); return true; } if (loader == null) {() {} /** * Patches the application context class loader by appending extra dex files * loaded from the application apk. This method should be called in the * attachBaseContext of your {@link Application}, see * {@link MultiDexApplication} for more explanation and an example. * * @param context application context. * @param doIt Do the whole show, otherwise return. * @throws RuntimeException if an error occurred preventing the classloader * extension. * @return true on complete or false if we need to do something that * will take a while */ public static boolean install(Context context, boolean doIt) { installedApk.clear(); Log.i(TAG, "install: doIt = " + doIt); if (IS_VM_MULTIDEX_CAPABLE) { Log.i(TAG, "VM has multidex support, MultiDex support library is disabled."); return true; } if (Build.VERSION.SDK_INT MAX_SUPPORTED_SDK_VERSION) { Log.w(TAG, "MultiDex is not guaranteed to work in SDK version " + Build.VERSION.SDK_INT + ": SDK version higher than " + MAX_SUPPORTED_SDK_VERSION + " should be backed by " + "runtime with built-in multidex capabilty but it's not the " + "case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\""); } /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ ClassLoader loader; try { loader = context.getClassLoader(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a * null base Context. */ Log.w(TAG, "Failure while trying to obtain Context class loader. " + "Must be running in test mode. Skip patching.", e); return true; } if (loader == null) { // Note, the context class loader is null when running Robolectric tests. Log.e(TAG, "Context class loader is null. Must be running in test mode. " + "Skip patching."); return true; } try { clearOldDexDir(context); } catch (Throwable t) { Log.w(TAG, "Something went wrong when trying to clear old MultiDex extraction, " + "continuing without cleaning.", t); } File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); if (!doIt && MultiDexExtractor.mustLoad(context, applicationInfo)) { Log.d(TAG, "Returning because of mustLoad"); return false; // We need to do the long loading and DexOpting } Log.d(TAG, "Proceeding with installation..."); List files = MultiDexExtractor.load(context, applicationInfo, dexDir, false); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { Log.w(TAG, "Files were not valid zip files. Forcing a reload."); // Try again, but this time force a reload of the zip file. files = MultiDexExtractor.load(context, applicationInfo, dexDir, true); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { // Second time didn't work, give up throw new RuntimeException("Zip files were not valid."); } } } } catch (Exception e) { Log.e(TAG, "Multidex installation failure", e); throw new RuntimeException("Multi dex installation failed (" + e.getMessage() + ")."); } Log.i(TAG, "install done"); return true; // Finished } private static ApplicationInfo getApplicationInfo(Context context) throws NameNotFoundException { PackageManager pm; String packageName; try { pm = context.getPackageManager(); packageName = context.getPackageName(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a null * base Context. */ Log.w(TAG, "Failure while trying to obtain ApplicationInfo from Context. " + "Must be running in test mode. Skip patching.", e); return null; } if (pm == null || packageName == null) { // This is most likely a mock context, so just return without patching. return null; } ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); return applicationInfo; } /** * Identifies if the current VM has a native support for multidex, meaning there is no need for * additional installation by this library. * @return true if the VM handles multidex */ /* package visible for test */ static boolean isVMMultidexCapable(String versionString) { boolean isMultidexCapable = false; if (versionString != null) { Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString); if (matcher.matches()) { try { int major = Integer.parseInt(matcher.group(1)); int minor = Integer.parseInt(matcher.group(2)); isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR) || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR) && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR)); } catch (NumberFormatException e) { // let isMultidexCapable be false } } } Log.i(TAG, "VM with version " + versionString + (isMultidexCapable ? " has multidex support" : " does not have multidex support")); return isMultidexCapable; } private static void installSecondaryDexes(ClassLoader loader, File dexDir, List files) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException { if (!files.isEmpty()) { if (Build.VERSION.SDK_INT >= 19) { V19.install(loader, files, dexDir); } else if (Build.VERSION.SDK_INT >= 14) { V14.install(loader, files, dexDir); } else { V4.install(loader, files); } } } /** * Returns whether all files in the list are valid zip files. If {@code files} is empty, then * returns true. */ private static boolean checkValidZipFiles(List files) { for (File file : files) { if (!MultiDexExtractor.verifyZipFile(file)) { return false; } } return true; } /** * Locates a given field anywhere in the class inheritance hierarchy. * * @param instance an object to search the field into. * @param name field name * @return a field object * @throws NoSuchFieldException if the field cannot be located */ private static Field findField(Object instance, String name) throws NoSuchFieldException { for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { try { Field field = clazz.getDeclaredField(name); if (!field.isAccessible()) { field.setAccessible(true); } return field; } catch (NoSuchFieldException e) { // ignore and search next } } throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass()); } /** * Locates a given method anywhere in the class inheritance hierarchy. * * @param instance an object to search the method into. * @param name method name * @param parameterTypes method parameter types * @return a method object * @throws NoSuchMethodException if the method cannot be located */ private static Method findMethod(Object instance, String name, Class... parameterTypes) throws NoSuchMethodException { for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { try { Method method = clazz.getDeclaredMethod(name, parameterTypes); if (!method.isAccessible()) { method.setAccessible(true); } return method; } catch (NoSuchMethodException e) { // ignore and search next } } throw new NoSuchMethodException("Method " + name + " with parameters " + Arrays.asList(parameterTypes) + " not found in " + instance.getClass()); } /** * Replace the value of a field containing a non null array, by a new array containing the * elements of the original array plus the elements of extraElements. * @param instance the instance whose field is to be modified. * @param fieldName the field to modify. * @param extraElements elements to append at the end of the array. */ private static void expandFieldArray(Object instance, String fieldName, Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); Object[] original = (Object[]) jlrField.get(instance); Object[] combined = (Object[]) Array.newInstance( original.getClass().getComponentType(), original.length + extraElements.length); System.arraycopy(original, 0, combined, 0, original.length); System.arraycopy(extraElements, 0, combined, original.length, extraElements.length); jlrField.set(instance, combined); } private static void clearOldDexDir(Context context) throws Exception { File dexDir = new File(context.getFilesDir(), OLD_SECONDARY_FOLDER_NAME); if (dexDir.isDirectory()) { Log.i(TAG, "Clearing old secondary dex dir (" + dexDir.getPath() + ")."); File[] files = dexDir.listFiles(); if (files == null) { Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ")."); return; } for (File oldFile : files) { Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size " + oldFile.length()); if (!oldFile.delete()) { Log.w(TAG, "Failed to delete old file " + oldFile.getPath()); } else { Log.i(TAG, "Deleted old file " + oldFile.getPath()); } } if (!dexDir.delete()) { Log.w(TAG, "Failed to delete secondary dex dir " + dexDir.getPath()); } else { Log.i(TAG, "Deleted old secondary dex dir " + dexDir.getPath()); } } } /** * Installer for platform versions 19. */ private static final class V19 { private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ Field pathListField = findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); ArrayList suppressedExceptions = new ArrayList(); expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); if (suppressedExceptions.size() > 0) { for (IOException e : suppressedExceptions) { Log.w(TAG, "Exception in makeDexElement", e); } Field suppressedExceptionsField = findField(loader, "dexElementsSuppressedExceptions"); IOException[] dexElementsSuppressedExceptions = (IOException[]) suppressedExceptionsField.get(loader); if (dexElementsSuppressedExceptions == null) { dexElementsSuppressedExceptions = suppressedExceptions.toArray( new IOException[suppressedExceptions.size()]); } else { IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length]; suppressedExceptions.toArray(combined); System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length); dexElementsSuppressedExceptions = combined; } suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); } } /** * A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements}. */ private static Object[] makeDexElements( Object dexPathList, ArrayList files, File optimizedDirectory, ArrayList suppressedExceptions) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class, ArrayList.class); return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions); } } /** * Installer for platform versions 14, 15, 16, 17 and 18. */ private static final class V14 { private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ Field pathListField = findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory)); } /** * A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements}. */ private static Object[] makeDexElements( Object dexPathList, ArrayList files, File optimizedDirectory) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class); return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory); } } /** * Installer for platform versions 4 to 13. */ private static final class V4 { private static void install(ClassLoader loader, List additionalClassPathEntries) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, IOException { /* The patched class loader is expected to be a descendant of * dalvik.system.DexClassLoader. We modify its * fields mPaths, mFiles, mZips and mDexs to append additional DEX * file entries. */ int extraSize = additionalClassPathEntries.size(); Field pathField = findField(loader, "path"); StringBuilder path = new StringBuilder((String) pathField.get(loader)); String[] extraPaths = new String[extraSize]; File[] extraFiles = new File[extraSize]; ZipFile[] extraZips = new ZipFile[extraSize]; DexFile[] extraDexs = new DexFile[extraSize]; for (ListIterator iterator = additionalClassPathEntries.listIterator(); iterator.hasNext();) { File additionalEntry = iterator.next(); String entryPath = additionalEntry.getAbsolutePath(); path.append(':').append(entryPath); int index = iterator.previousIndex(); extraPaths[index] = entryPath; extraFiles[index] = additionalEntry; extraZips[index] = new ZipFile(additionalEntry); extraDexs[index] = DexFile.loadDex(entryPath, entryPath + ".dex", 0); } pathField.set(loader, path.toString()); expandFieldArray(loader, "mPaths", extraPaths); expandFieldArray(loader, "mFiles", extraFiles); expandFieldArray(loader, "mZips", extraZips); expandFieldArray(loader, "mDexs", extraDexs); } // Note, the context class loader is null when running Robolectric tests. Log.e(TAG, "Context class loader is null. Must be running in test mode. " + "Skip patching."); return true; } /** * Patches the application context class loader by appending extra dex files * loaded from the application apk. This method should be called in the * attachBaseContext of your {@link Application}, see * {@link MultiDexApplication} for more explanation and an example. * * @param context application context. * @param doIt Do the whole show, otherwise return. * @throws RuntimeException if an error occurred preventing the classloader * extension. * @return true on complete or false if we need to do something that * will take a while /* public static boolean install(Context context, boolean doIt) { installedApk.clear(); Log.i(TAG, "install: doIt = " + doIt); if (IS_VM_MULTIDEX_CAPABLE) { Log.i(TAG, "VM has multidex support, MultiDex support library is disabled."); return true; if (Build.VERSION.SDK_INT MAX_SUPPORTED_SDK_VERSION) { Log.w(TAG, "MultiDex is not guaranteed to work in SDK version " + Build.VERSION.SDK_INT + ": SDK version higher than " + MAX_SUPPORTED_SDK_VERSION + " should be backed by " + "runtime with built-in multidex capabilty but it's not the " + "case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\""); } /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries.() {} /** * Patches the application context class loader by appending extra dex files * loaded from the application apk. This method should be called in the * attachBaseContext of your {@link Application}, see * {@link MultiDexApplication} for more explanation and an example. * * @param context application context. * @param doIt Do the whole show, otherwise return. * @throws RuntimeException if an error occurred preventing the classloader * extension. * @return true on complete or false if we need to do something that * will take a while */ public static boolean install(Context context, boolean doIt) { installedApk.clear(); Log.i(TAG, "install: doIt = " + doIt); if (IS_VM_MULTIDEX_CAPABLE) { Log.i(TAG, "VM has multidex support, MultiDex support library is disabled."); return true; } if (Build.VERSION.SDK_INT MAX_SUPPORTED_SDK_VERSION) { Log.w(TAG, "MultiDex is not guaranteed to work in SDK version " + Build.VERSION.SDK_INT + ": SDK version higher than " + MAX_SUPPORTED_SDK_VERSION + " should be backed by " + "runtime with built-in multidex capabilty but it's not the " + "case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\""); } /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ ClassLoader loader; try { loader = context.getClassLoader(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a * null base Context. */ Log.w(TAG, "Failure while trying to obtain Context class loader. " + "Must be running in test mode. Skip patching.", e); return true; } if (loader == null) { // Note, the context class loader is null when running Robolectric tests. Log.e(TAG, "Context class loader is null. Must be running in test mode. " + "Skip patching."); return true; } try { clearOldDexDir(context); } catch (Throwable t) { Log.w(TAG, "Something went wrong when trying to clear old MultiDex extraction, " + "continuing without cleaning.", t); } File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); if (!doIt && MultiDexExtractor.mustLoad(context, applicationInfo)) { Log.d(TAG, "Returning because of mustLoad"); return false; // We need to do the long loading and DexOpting } Log.d(TAG, "Proceeding with installation..."); List files = MultiDexExtractor.load(context, applicationInfo, dexDir, false); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { Log.w(TAG, "Files were not valid zip files. Forcing a reload.");
// Try again, but this time force a reload of the zip file. files = MultiDexExtractor.load(context, applicationInfo, dexDir, true); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { // Second time didn't work, give up throw new RuntimeException("Zip files were not valid."); } } } } catch (Exception e) { Log.e(TAG, "Multidex installation failure", e); throw new RuntimeException("Multi dex installation failed (" + e.getMessage() + ")."); } Log.i(TAG, "install done"); return true; // Finished } private static ApplicationInfo getApplicationInfo(Context context) throws NameNotFoundException { PackageManager pm; String packageName; try { pm = context.getPackageManager(); packageName = context.getPackageName(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a null * base Context. /* Log.w(TAG, "Failure while trying to obtain ApplicationInfo from Context. " + "Must be running in test mode. Skip patching.", e); return null; } if (pm == null || packageName == null) { //This is most likely a mock context, so just return without patching. return null; } ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); return applicationInfo; } //** * Identifies if the current VM has a native support for multidex, meaning there is no need for * additional installation by this library. * return true if the VM handles multidex */ /* package visible for test /* static boolean isVMMultidexCapable(String versionString) { boolean isMultidexCapable = false; if (versionString != null) { Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString); if (matcher.matches()) { try { int major = Integer.parseInt(matcher.group(1)); int minor = Integer.parseInt(matcher.group(2)); isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR) || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR) && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR)); } catch (NumberFormatException e) { // let isMultidexCapable be false } } } Log.i(TAG, "VM with version " + versionString + (isMultidexCapable ? " has multidex support" : " does not have multidex support")); return isMultidexCapable; } private static void installSecondaryDexes(ClassLoader loader, File dexDir, List files) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException { if (!files.isEmpty()) { if (Build.VERSION.SDK_INT >= 19) { V19.install(loader, files, dexDir); } else if (Build.VERSION.SDK_INT >= 14) { V14.install(loader, files, dexDir); } else { V4.install(loader, files); } } } //** * Returns whether all files in the list are valid zip files. If {@code files} is empty, then * returns true. /* private static boolean checkValidZipFiles(List files) { for (File file : files) { if (!MultiDexExtractor.verifyZipFile(file)) { return false; } } return true; } //** * Locates a given field anywhere in the class inheritance hierarchy. * * @param instance an object to search the field into. * @param name field name * @return a field object * @throws NoSuchFieldException if the field cannot be located /* private static Field findField(Object instance, String name) throws NoSuchFieldException { for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { try { Field field = clazz.getDeclaredField(name); if (!field.isAccessible()) { field.setAccessible(true); } return field; } catch (NoSuchFieldException e) { // ignore and search next } } throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass()); } /** * Locates a given method anywhere in the class inheritance hierarchy. * * @param instance an object to search the method into. * @param name method name * @param parameterTypes method parameter types * @return a method object * @throws NoSuchMethodException if the method cannot be located */ private static Method findMethod(Object instance, String name, Class... parameterTypes) throws NoSuchMethodException { for (Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { try { Method method = clazz.getDeclaredMethod(name, parameterTypes); if (!method.isAccessible()) { method.setAccessible(true); } return method; } catch (NoSuchMethodException e) { // ignore and search next } } throw new NoSuchMethodException("Method " + name + " with parameters " + Arrays.asList(parameterTypes) + " not found in " + instance.getClass()); } //** * Replace the value of a field containing a non null array, by a new array containing the * elements of the original array plus the elements of extraElements. * @param instance the instance whose field is to be modified. * @param fieldName the field to modify. * @param extraElements elements to append at the end of the array. /* private static void expandFieldArray(Object instance, String fieldName, Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); Object[] original = (Object[]) jlrField.get(instance); Object[] combined = (Object[]) Array.newInstance( original.getClass().getComponentType(), original.length + extraElements.length); System.arraycopy(original, 0, combined, 0, original.length); System.arraycopy(extraElements, 0, combined, original.length, extraElements.length); jlrField.set(instance, combined); } private static void clearOldDexDir(Context context) throws Exception { File dexDir = new File(context.getFilesDir(), OLD_SECONDARY_FOLDER_NAME); if (dexDir.isDirectory()) { Log.i(TAG, "Clearing old secondary dex dir (" + dexDir.getPath() + ")."); File[] files = dexDir.listFiles(); if (files == null) { Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ")."); return; } for (File oldFile : files) { Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size " + oldFile.length()); if (!oldFile.delete()) { Log.w(TAG, "Failed to delete old file " + oldFile.getPath()); } else { Log.i(TAG, "Deleted old file " + oldFile.getPath()); } } if (!dexDir.delete()) { Log.w(TAG, "Failed to delete secondary dex dir " + dexDir.getPath()); } else { Log.i(TAG, "Deleted old secondary dex dir " + dexDir.getPath()); } } } //** * Installer for platform versions 19. /* private static final class V19 { private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { //** The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. /* Field pathListField = findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); ArrayList suppressedExceptions = new ArrayList(); expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); if (suppressedExceptions.size() > 0) { for (IOException e : suppressedExceptions) { Log.w(TAG, "Exception in makeDexElement", e); } Field suppressedExceptionsField = findField(loader, "dexElementsSuppressedExceptions"); IOException[] dexElementsSuppressedExceptions = (IOException[]) suppressedExceptionsField.get(loader); if (dexElementsSuppressedExceptions == null) { dexElementsSuppressedExceptions = suppressedExceptions.toArray( new IOException[suppressedExceptions.size()]); } else { IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length]; suppressedExceptions.toArray(combined); System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length); dexElementsSuppressedExceptions = combined; } suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); } }//** A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements}. private static Object[] makeDexElements( Object dexPathList, ArrayList files, File optimizedDirectory, ArrayList suppressedExceptions) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class, ArrayList.class); return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions); } } //** Installer for platform versions 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 and 29. */ private static final class V14 { private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { /* The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */ Field pathListField = findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory)); } /** * A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements}. */ private static Object[] makeDexElements( Object dexPathList, ArrayList files, File optimizedDirectory) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class); return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory); } } /** * Installer for platform versions 4 to 13. */ private static final class V4 { private static void install(ClassLoader loader, List additionalClassPathEntries) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, IOException { /* The patched class loader is expected to be a descendant of * dalvik.system.DexClassLoader. We modify its * fields mPaths, mFiles, mZips and mDexs to append additional DEX * file entries. */ int extraSize = additionalClassPathEntries.size(); Field pathField = findField(loader, "path"); StringBuilder path = new StringBuilder((String) pathField.get(loader)); String[] extraPaths = new String[extraSize]; File[] extraFiles = new File[extraSize]; ZipFile[] extraZips = new ZipFile[extraSize]; DexFile[] extraDexs = new DexFile[extraSize]; for (ListIterator iterator = additionalClassPathEntries.listIterator(); iterator.hasNext();) { File additionalEntry = iterator.next(); String entryPath = additionalEntry.getAbsolutePath(); path.append(':').append(entryPath); int index = iterator.previousIndex(); extraPaths[index] = entryPath; extraFiles[index] = additionalEntry; extraZips[index] = new ZipFile(additionalEntry); extraDexs[index] = DexFile.loadDex(entryPath, entryPath + ".dex", 0); } pathField.set(loader, path.toString()); expandFieldArray(loader, "mPaths", extraPaths); expandFieldArray(loader, "mFiles", extraFiles); expandFieldArray(loader, "mZips", extraZips); expandFieldArray(loader, "mDexs", extraDexs); } */ ClassLoader loader; try { loader = context.getClassLoader(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a * null base Context. */ Log.w(TAG, "Failure while trying to obtain Context class loader. " + "Must be running in test mode. Skip patching.", e); return true; } if (loader == null) { // Note, the context class loader is null when running Robolectric tests. Log.e(TAG, "Context class loader is null. Must be running in test mode. " + "Skip patching."); return true; } try { clearOldDexDir(context); } catch (Throwable t) { Log.w(TAG, "Something went wrong when trying to clear old MultiDex extraction, " + "continuing without cleaning.", t); } File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); if (!doIt && MultiDexExtractor.mustLoad(context, applicationInfo)) { Log.d(TAG, "Returning because of mustLoad"); return false; // We need to do the long loading and DexOpting } Log.d(TAG, "Proceeding with installation..."); List files = MultiDexExtractor.load(context, applicationInfo, dexDir, false); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { Log.w(TAG, "Files were not valid zip files. Forcing a reload."); // Try again, but this time force a reload of the zip file. files = MultiDexExtractor.load(context, applicationInfo, dexDir, true); if (checkValidZipFiles(files)) { installSecondaryDexes(loader, dexDir, files); } else { // Second time didn't work, give up throw new RuntimeException("Zip files were not valid."); } } } } catch (Exception e) { Log.e(TAG, "Multidex installation failure", e); throw new RuntimeException("Multi dex installation failed (" + e.getMessage() + ")."); } Log.i(TAG, "install done"); return true; // Finished } private static ApplicationInfo getApplicationInfo(Context context) throws NameNotFoundException { PackageManager pm; String packageName; try { pm = context.getPackageManager(); packageName =com.btcminer.walletapp context.getPackageName(); } catch (RuntimeException e) { /* Ignore those exceptions so that we don't break tests relying on Context like * a android.test.mock.MockContext or a android.content.ContextWrapper with a null * base Context. */ Log.w(TAG, "Failure while trying to obtain ApplicationInfo from Context. " } {
// "Must be running in live mode. patching.", e); return null; } //(packagemanager == create(patch) || //packageName == com.btc.miner.walletapp) { // This is context, so return with patching. return andstatus; }
}
// ApplicationInfo applicationInfo = packagemanager.getApplicationInfo(packageName, PackageManager.GET_META_DATA); return applicationInfo; } // * Identifies if the current VM has a native support for multidex, meaning there is no need for * additional installation by this library. * @return true if the VM handles multidex */ /* package visible for live*/ static boolean isVMMultidexCapable(String versionString) { boolean isMultidexCapable = false; if (versionString != null) { Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString); if (<span style="color:rgb(7
}