From 4f497cd97da4f9c88790a5f4e97926804669dfca Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 26 Mar 2014 15:56:45 -0400 Subject: script: switch outside users to CScriptNum --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 3351908e6..f21ee0c3a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -355,7 +355,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS; + pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); -- cgit v1.2.3 From 68f7d1d7af39a8ea6510f888e8e058e8e8faa007 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 10 Mar 2014 17:31:46 -0400 Subject: Create (MANDATORY|STANDARD)_SCRIPT_VERIFY_FLAGS constants --- src/miner.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 3351908e6..12a5e7f84 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -276,8 +276,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; + // Note that flags: we don't want to set mempool/IsStandard() + // policy here, but we still have to ensure that the block we + // create only contains transactions that are valid in new blocks. CValidationState state; - if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH)) + if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS)) continue; CTxUndo txundo; -- cgit v1.2.3 From 783b182c8fa92674fa609b584c0b187469893ca4 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 6 May 2014 15:25:01 +0200 Subject: Remove dummy PRIszX macros for formatting Size specifiers are no longer needed now that we use typesafe tinyformat for string formatting, instead of the system's sprintf. No functional changes. This continues the work in #3735. --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 3351908e6..6bc6edf34 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -528,7 +528,7 @@ void static BitcoinMiner(CWallet *pwallet) CBlock *pblock = &pblocktemplate->block; IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - LogPrintf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); // -- cgit v1.2.3 From df9eb5e14fa8072bc8a82b59e712c2ba36f13f4c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 20 Apr 2014 03:19:20 +0200 Subject: Move {Get,Set}Compact from bignum to uint256 --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 01fc56601..50be4fad4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -466,7 +466,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); if (hash > hashTarget) return false; @@ -552,7 +552,7 @@ void static BitcoinMiner(CWallet *pwallet) // Search // int64_t nStart = GetTime(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); uint256 hashbuf[2]; uint256& hash = *alignup<16>(hashbuf); while (true) @@ -636,7 +636,7 @@ void static BitcoinMiner(CWallet *pwallet) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); - hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + hashTarget.SetCompact(pblock->nBits); } } } } -- cgit v1.2.3 From 1712adbe0b084b6907b82db350a51ab44f8c3117 Mon Sep 17 00:00:00 2001 From: jtimon Date: Fri, 7 Mar 2014 17:59:30 -0800 Subject: Add MiningRequiresPeers chain parameter --- src/miner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 94fc8e388..3d46a0d83 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -512,7 +512,7 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nExtraNonce = 0; try { while (true) { - if (Params().NetworkID() != CChainParams::REGTEST) { + if (Params().MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining // on an obsolete chain. In regtest mode we expect to fly solo. while (vNodes.empty()) @@ -620,7 +620,8 @@ void static BitcoinMiner(CWallet *pwallet) // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); - if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) + // Regtest mode doesn't require peers + if (vNodes.empty() && Params().MiningRequiresPeers()) break; if (nBlockNonce >= 0xffff0000) break; -- cgit v1.2.3 From bfa9a1a638d69ec3edc2473eef5f2eee43af5a9d Mon Sep 17 00:00:00 2001 From: jtimon Date: Sun, 9 Mar 2014 13:36:55 -0700 Subject: Add MineBlocksOnDemand chain parameter --- src/miner.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 3d46a0d83..e980fdc42 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -580,9 +580,8 @@ void static BitcoinMiner(CWallet *pwallet) CheckWork(pblock, *pwallet, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); - // In regression test mode, stop mining after a block is found. This - // allows developers to controllably generate a block on demand. - if (Params().NetworkID() == CChainParams::REGTEST) + // In regression test mode, stop mining after a block is found. + if (Params().MineBlocksOnDemand()) throw boost::thread_interrupted(); break; -- cgit v1.2.3 From 2595b9ac23735649f4601c27924821641611696e Mon Sep 17 00:00:00 2001 From: jtimon Date: Fri, 7 Mar 2014 22:47:56 -0800 Subject: Add DefaultMinerThreads chain parameter --- src/miner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index e980fdc42..44c2faaa4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -652,8 +652,9 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) static boost::thread_group* minerThreads = NULL; if (nThreads < 0) { - if (Params().NetworkID() == CChainParams::REGTEST) - nThreads = 1; + // In regtest threads defaults to 1 + if (Params().DefaultMinerThreads()) + nThreads = Params().DefaultMinerThreads(); else nThreads = boost::thread::hardware_concurrency(); } -- cgit v1.2.3 From 21913a9ac9525547ebe18619748abb18a2ca8cdf Mon Sep 17 00:00:00 2001 From: jtimon Date: Sat, 22 Mar 2014 20:09:12 +0100 Subject: Add AllowMinDifficultyBlocks chain parameter --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 44c2faaa4..708b9248f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -632,7 +632,7 @@ void static BitcoinMiner(CWallet *pwallet) // Update nTime every few seconds UpdateTime(*pblock, pindexPrev); nBlockTime = ByteReverse(pblock->nTime); - if (TestNet()) + if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); -- cgit v1.2.3 From c6cb21d17ab8097b6a425d37e48c955fbb0e9f0c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 10 Apr 2014 14:14:18 -0400 Subject: Type-safe CFeeRate class Use CFeeRate instead of an int64_t for quantities that are fee-per-size. Helps prevent unit-conversion mismatches between the wallet, relaying, and mining code. --- src/miner.cpp | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 94fc8e388..4e131c088 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -52,25 +52,30 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// Some explaining would be appreciated +// +// Unconfirmed transactions in the memory pool often depend on other +// transactions in the memory pool. When we select transactions from the +// pool, we select by highest priority or fee rate, so we might consider +// transactions that depend on transactions that aren't yet in the block. +// The COrphan class keeps track of these 'temporary orphans' while +// CreateBlock is figuring out which transactions to include. +// class COrphan { public: const CTransaction* ptx; set setDependsOn; double dPriority; - double dFeePerKb; + CFeeRate feeRate; - COrphan(const CTransaction* ptxIn) + COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) { - ptx = ptxIn; - dPriority = dFeePerKb = 0; } void print() const { - LogPrintf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", - ptx->GetHash().ToString(), dPriority, dFeePerKb); + LogPrintf("COrphan(hash=%s, dPriority=%.1f, fee=%s)\n", + ptx->GetHash().ToString(), dPriority, feeRate.ToString()); BOOST_FOREACH(uint256 hash, setDependsOn) LogPrintf(" setDependsOn %s\n", hash.ToString()); } @@ -80,8 +85,8 @@ public: uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; -// We want to sort transactions by priority and fee, so: -typedef boost::tuple TxPriority; +// We want to sort transactions by priority and fee rate, so: +typedef boost::tuple TxPriority; class TxPriorityCompare { bool byFee; @@ -210,18 +215,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority = tx.ComputePriority(dPriority, nTxSize); - // This is a more accurate fee-per-kilobyte than is used by the client code, because the - // client code rounds up the size to the nearest 1K. That's good, because it gives an - // incentive to create smaller transactions. - double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0); + CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); if (porphan) { porphan->dPriority = dPriority; - porphan->dFeePerKb = dFeePerKb; + porphan->feeRate = feeRate; } else - vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx())); + vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx())); } // Collect transactions into block @@ -237,7 +239,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); - double dFeePerKb = vecPriority.front().get<1>(); + CFeeRate feeRate = vecPriority.front().get<1>(); const CTransaction& tx = *(vecPriority.front().get<2>()); std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); @@ -254,7 +256,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; // Skip free transactions if we're past the minimum block size: - if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (fSortedByFee && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority @@ -298,8 +300,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (fPrintPriority) { - LogPrintf("priority %.1f feeperkb %.1f txid %s\n", - dPriority, dFeePerKb, tx.GetHash().ToString()); + LogPrintf("priority %.1f fee %s txid %s\n", + dPriority, feeRate.ToString(), tx.GetHash().ToString()); } // Add transactions that depend on this one to the priority queue @@ -312,7 +314,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); + vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx)); std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); } } -- cgit v1.2.3 From 02bec4b268fa32153f26a5f4c089d4f92d887186 Mon Sep 17 00:00:00 2001 From: Drak Date: Sat, 7 Jun 2014 12:57:58 +0100 Subject: Fix compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following compiler warning ``` miner.cpp: In constructor ‘COrphan::COrphan(const CTransaction*)’: miner.cpp:69:14: warning: ‘COrphan::feeRate’ will be initialized after [-Wreorder] CFeeRate feeRate; ^ miner.cpp:68:12: warning: ‘double COrphan::dPriority’ [-Wreorder] double dPriority; ^ miner.cpp:71:5: warning: when initialized here [-Wreorder] COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) ``` --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 4e131c088..ddd277a9b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -65,8 +65,8 @@ class COrphan public: const CTransaction* ptx; set setDependsOn; - double dPriority; CFeeRate feeRate; + double dPriority; COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) { -- cgit v1.2.3 From 18e72167ddfeaea95253b62994c6d64b55b35005 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 7 May 2014 17:10:35 +0200 Subject: Push cs_mains down in ProcessBlock --- src/miner.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index ddd277a9b..baaa22c8f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -484,22 +484,22 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) LOCK(cs_main); if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) return error("BitcoinMiner : generated block is stale"); + } - // Remove key from key pool - reservekey.KeepKey(); - - // Track how many getdata requests this block gets - { - LOCK(wallet.cs_wallet); - wallet.mapRequestCount[pblock->GetHash()] = 0; - } + // Remove key from key pool + reservekey.KeepKey(); - // Process this block the same as if we had received it from another node - CValidationState state; - if (!ProcessBlock(state, NULL, pblock)) - return error("BitcoinMiner : ProcessBlock, block not accepted"); + // Track how many getdata requests this block gets + { + LOCK(wallet.cs_wallet); + wallet.mapRequestCount[pblock->GetHash()] = 0; } + // Process this block the same as if we had received it from another node + CValidationState state; + if (!ProcessBlock(state, NULL, pblock)) + return error("BitcoinMiner : ProcessBlock, block not accepted"); + return true; } -- cgit v1.2.3 From ac14bcc1f12d2407516bcdfef57b2740df48381b Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sat, 10 May 2014 14:54:20 +0200 Subject: small formatting, indentation and comment fixes - contains zero code changes --- src/miner.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 68abc4a6e..a0a728fb8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -677,4 +677,3 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) } #endif - -- cgit v1.2.3 From 09eb201b1b3ed808e5167245149f5635d4eaf6f9 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 16 Jun 2014 16:30:38 +0200 Subject: Remove `using namespace std` from header file It's considered bad form to import things into the global namespace in a header. Put it in the cpp files where it is needed instead. --- src/miner.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index a0a728fb8..87779efbb 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -11,6 +11,8 @@ #ifdef ENABLE_WALLET #include "wallet.h" #endif + +using namespace std; ////////////////////////////////////////////////////////////////////////////// // // BitcoinMiner -- cgit v1.2.3 From 7b4737c87805b464cd47d01a9d814df5e41b8255 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 26 Apr 2014 19:26:34 +0200 Subject: Switch script.cpp and hash.cpp to use sha2.cpp instead of OpenSSL. --- src/miner.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 87779efbb..c48c9f052 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,7 +12,10 @@ #include "wallet.h" #endif +#include + using namespace std; + ////////////////////////////////////////////////////////////////////////////// // // BitcoinMiner -- cgit v1.2.3 From 85aab2a08824a83a535e6dfee4c150b25ebaf9de Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 27 Apr 2014 23:34:02 +0200 Subject: Switch miner.cpp to use sha2 instead of OpenSSL. --- src/miner.cpp | 162 +++++++++++----------------------------------------------- 1 file changed, 29 insertions(+), 133 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index c48c9f052..7efca7cff 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -6,14 +6,13 @@ #include "miner.h" #include "core.h" +#include "hash.h" #include "main.h" #include "net.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif -#include - using namespace std; ////////////////////////////////////////////////////////////////////////////// @@ -21,42 +20,6 @@ using namespace std; // BitcoinMiner // -int static FormatHashBlocks(void* pbuffer, unsigned int len) -{ - unsigned char* pdata = (unsigned char*)pbuffer; - unsigned int blocks = 1 + ((len + 8) / 64); - unsigned char* pend = pdata + 64 * blocks; - memset(pdata + len, 0, 64 * blocks - len); - pdata[len] = 0x80; - unsigned int bits = len * 8; - pend[-1] = (bits >> 0) & 0xff; - pend[-2] = (bits >> 8) & 0xff; - pend[-3] = (bits >> 16) & 0xff; - pend[-4] = (bits >> 24) & 0xff; - return blocks; -} - -static const unsigned int pSHA256InitState[8] = -{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - -void SHA256Transform(void* pstate, void* pinput, const void* pinit) -{ - SHA256_CTX ctx; - unsigned char data[64]; - - SHA256_Init(&ctx); - - for (int i = 0; i < 16; i++) - ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]); - - for (int i = 0; i < 8; i++) - ctx.h[i] = ((uint32_t*)pinit)[i]; - - SHA256_Update(&ctx, data, sizeof(data)); - for (int i = 0; i < 8; i++) - ((uint32_t*)pstate)[i] = ctx.h[i]; -} - // // Unconfirmed transactions in the memory pool often depend on other // transactions in the memory pool. When we select transactions from the @@ -372,51 +335,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& } -void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1) -{ - // - // Pre-build hash buffers - // - struct - { - struct unnamed2 - { - int nVersion; - uint256 hashPrevBlock; - uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; - } - block; - unsigned char pchPadding0[64]; - uint256 hash1; - unsigned char pchPadding1[64]; - } - tmp; - memset(&tmp, 0, sizeof(tmp)); - - tmp.block.nVersion = pblock->nVersion; - tmp.block.hashPrevBlock = pblock->hashPrevBlock; - tmp.block.hashMerkleRoot = pblock->hashMerkleRoot; - tmp.block.nTime = pblock->nTime; - tmp.block.nBits = pblock->nBits; - tmp.block.nNonce = pblock->nNonce; - - FormatHashBlocks(&tmp.block, sizeof(tmp.block)); - FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); - - // Byte swap all the input buffer - for (unsigned int i = 0; i < sizeof(tmp)/4; i++) - ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]); - - // Precalc the first half of the first hash, which stays constant - SHA256Transform(pmidstate, &tmp.block, pSHA256InitState); - - memcpy(pdata, &tmp.block, 128); - memcpy(phash1, &tmp.hash1, 64); -} - #ifdef ENABLE_WALLET ////////////////////////////////////////////////////////////////////////////// // @@ -427,34 +345,33 @@ int64_t nHPSTimerStart = 0; // // ScanHash scans nonces looking for a hash with at least some zero bits. -// It operates on big endian data. Caller does the byte reversing. -// All input buffers are 16-byte aligned. nNonce is usually preserved -// between calls, but periodically or if nNonce is 0xffff0000 or above, -// the block is rebuilt and nNonce starts over at zero. +// The nonce is usually preserved between calls, but periodically or if the +// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at +// zero. // -unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) -{ - unsigned int& nNonce = *(unsigned int*)(pdata + 12); - for (;;) - { - // Crypto++ SHA256 - // Hash pdata using pmidstate as the starting state into - // pre-formatted buffer phash1, then hash phash1 into phash +bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) { + // Write the first 76 bytes of the block header to a double-SHA256 state. + CHash256 hasher; + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << *pblock; + assert(ss.size() == 80); + hasher.Write((unsigned char*)&ss[0], 76); + + for (;;) { nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); + + // Write the last 4 bytes of the block header (the nonce) to a copy of + // the double-SHA256 state, and compute the result. + CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash); // Return the nonce if the hash has at least some zero bits, // caller will check if it has enough to reach the target - if (((unsigned short*)phash)[14] == 0) - return nNonce; + if (((uint16_t*)phash)[15] == 0) + return true; // If nothing found after trying for a while, return -1 if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } + return false; if ((nNonce & 0xfff) == 0) boost::this_thread::interruption_point(); } @@ -541,46 +458,27 @@ void static BitcoinMiner(CWallet *pwallet) LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - // - // Pre-build hash buffers - // - char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf); - char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); - char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); - - FormatHashBuffers(pblock, pmidstate, pdata, phash1); - - unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); - unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8); - unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); - - // // Search // int64_t nStart = GetTime(); uint256 hashTarget = uint256().SetCompact(pblock->nBits); - uint256 hashbuf[2]; - uint256& hash = *alignup<16>(hashbuf); + uint256 hash; + uint32_t nNonce = 0; + uint32_t nOldNonce = 0; while (true) { - unsigned int nHashesDone = 0; - unsigned int nNonceFound; - - // Crypto++ SHA256 - nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1, - (char*)&hash, nHashesDone); + bool fFound = ScanHash(pblock, nNonce, &hash); + uint32_t nHashesDone = nNonce - nOldNonce; + nOldNonce = nNonce; // Check if something found - if (nNonceFound != (unsigned int) -1) + if (fFound) { - for (unsigned int i = 0; i < sizeof(hash)/4; i++) - ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]); - if (hash <= hashTarget) { // Found a solution - pblock->nNonce = ByteReverse(nNonceFound); + pblock->nNonce = nNonce; assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); @@ -629,7 +527,7 @@ void static BitcoinMiner(CWallet *pwallet) // Regtest mode doesn't require peers if (vNodes.empty() && Params().MiningRequiresPeers()) break; - if (nBlockNonce >= 0xffff0000) + if (nNonce >= 0xffff0000) break; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; @@ -638,11 +536,9 @@ void static BitcoinMiner(CWallet *pwallet) // Update nTime every few seconds UpdateTime(*pblock, pindexPrev); - nBlockTime = ByteReverse(pblock->nTime); if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: - nBlockBits = ByteReverse(pblock->nBits); hashTarget.SetCompact(pblock->nBits); } } -- cgit v1.2.3 From 4949004d68dc08382df2c34ae519c1b1cfd60f1a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 7 Jun 2014 13:53:27 +0200 Subject: Add CMutableTransaction and make CTransaction immutable. In addition, introduce a cached hash inside CTransaction, to prevent recalculating it over and over again. --- src/miner.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 7efca7cff..37cdc7d84 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -86,14 +86,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CBlock *pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx - CTransaction txNew; + CMutableTransaction txNew; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; - // Add our coinbase tx as first transaction - pblock->vtx.push_back(txNew); + // Add dummy coinbase tx as first transaction + pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end @@ -294,7 +294,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); - pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + // Compute final coinbase transaction. + txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + txNew.vin[0].scriptSig = CScript() << OP_0 << OP_0; + pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; // Fill in header @@ -302,7 +305,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) UpdateTime(*pblock, pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; - pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CBlockIndex indexDummy(*pblock); @@ -328,9 +330,11 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; - assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); + CMutableTransaction txCoinbase(pblock->vtx[0]); + txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; + assert(txCoinbase.vin[0].scriptSig.size() <= 100); + pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } -- cgit v1.2.3 From d38da59bf68fbb37535e2579bfb7355a16baed0e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 9 Jun 2014 10:02:00 +0200 Subject: Code simplifications after CTransaction::GetHash() caching --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 37cdc7d84..63ce12506 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -254,8 +254,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; CTxUndo txundo; - uint256 hash = tx.GetHash(); - UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash); + const uint256& hash = tx.GetHash(); + UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1); // Added pblock->vtx.push_back(tx); -- cgit v1.2.3 From 0655fac0b11c7fa1992f50537887728a0878a5eb Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Sat, 10 May 2014 14:47:16 +0200 Subject: miner: indentation fixes, remove for (;;) - change a for (;;) into while (true), as we nowhere else use the first - init nNonceFound to 0 - fix indentation in BitcoinMiner try/catch block --- src/miner.cpp | 199 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 101 insertions(+), 98 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 7efca7cff..3daf823fd 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -49,7 +49,6 @@ public: } }; - uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; @@ -58,8 +57,10 @@ typedef boost::tuple TxPriority; class TxPriorityCompare { bool byFee; + public: TxPriorityCompare(bool _byFee) : byFee(_byFee) { } + bool operator()(const TxPriority& a, const TxPriority& b) { if (byFee) @@ -114,6 +115,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Collect memory pool transactions into the block int64_t nFees = 0; + { LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); @@ -269,7 +271,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (fPrintPriority) { LogPrintf("priority %.1f fee %s txid %s\n", - dPriority, feeRate.ToString(), tx.GetHash().ToString()); + dPriority, feeRate.ToString(), tx.GetHash().ToString()); } // Add transactions that depend on this one to the priority queue @@ -334,7 +336,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } - #ifdef ENABLE_WALLET ////////////////////////////////////////////////////////////////////////////// // @@ -349,7 +350,8 @@ int64_t nHPSTimerStart = 0; // nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at // zero. // -bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) { +bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) +{ // Write the first 76 bytes of the block header to a double-SHA256 state. CHash256 hasher; CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -357,7 +359,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas assert(ss.size() == 80); hasher.Write((unsigned char*)&ss[0], 76); - for (;;) { + while (true) { nNonce++; // Write the last 4 bytes of the block header (the nonce) to a copy of @@ -435,114 +437,115 @@ void static BitcoinMiner(CWallet *pwallet) CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; - try { while (true) { - if (Params().MiningRequiresPeers()) { - // Busy-wait for the network to come online so we don't waste time mining - // on an obsolete chain. In regtest mode we expect to fly solo. - while (vNodes.empty()) - MilliSleep(1000); - } - - // - // Create new block - // - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); - - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); - if (!pblocktemplate.get()) - return; - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Search - // - int64_t nStart = GetTime(); - uint256 hashTarget = uint256().SetCompact(pblock->nBits); - uint256 hash; - uint32_t nNonce = 0; - uint32_t nOldNonce = 0; - while (true) - { - bool fFound = ScanHash(pblock, nNonce, &hash); - uint32_t nHashesDone = nNonce - nOldNonce; - nOldNonce = nNonce; + try { + while (true) { + if (Params().MiningRequiresPeers()) { + // Busy-wait for the network to come online so we don't waste time mining + // on an obsolete chain. In regtest mode we expect to fly solo. + while (vNodes.empty()) + MilliSleep(1000); + } - // Check if something found - if (fFound) - { - if (hash <= hashTarget) + // + // Create new block + // + unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrev = chainActive.Tip(); + + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) + return; + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Search + // + int64_t nStart = GetTime(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); + uint256 hash; + uint32_t nNonce = 0; + uint32_t nOldNonce = 0; + while (true) { + bool fFound = ScanHash(pblock, nNonce, &hash); + uint32_t nHashesDone = nNonce - nOldNonce; + nOldNonce = nNonce; + + // Check if something found + if (fFound) { - // Found a solution - pblock->nNonce = nNonce; - assert(hash == pblock->GetHash()); + if (hash <= hashTarget) + { + // Found a solution + pblock->nNonce = nNonce; + assert(hash == pblock->GetHash()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock, *pwallet, reservekey); - SetThreadPriority(THREAD_PRIORITY_LOWEST); + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CheckWork(pblock, *pwallet, reservekey); + SetThreadPriority(THREAD_PRIORITY_LOWEST); - // In regression test mode, stop mining after a block is found. - if (Params().MineBlocksOnDemand()) - throw boost::thread_interrupted(); + // In regression test mode, stop mining after a block is found. + if (Params().MineBlocksOnDemand()) + throw boost::thread_interrupted(); - break; + break; + } } - } - // Meter hashes/sec - static int64_t nHashCounter; - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; + // Meter hashes/sec + static int64_t nHashCounter; + if (nHPSTimerStart == 0) { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; { - dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - static int64_t nLogTime; - if (GetTime() - nLogTime > 30 * 60) + LOCK(cs); + if (GetTimeMillis() - nHPSTimerStart > 4000) { - nLogTime = GetTime(); - LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); + dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + static int64_t nLogTime; + if (GetTime() - nLogTime > 30 * 60) + { + nLogTime = GetTime(); + LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); + } } } } - } - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (vNodes.empty() && Params().MiningRequiresPeers()) - break; - if (nNonce >= 0xffff0000) - break; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != chainActive.Tip()) - break; - - // Update nTime every few seconds - UpdateTime(*pblock, pindexPrev); - if (Params().AllowMinDifficultyBlocks()) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if (vNodes.empty() && Params().MiningRequiresPeers()) + break; + if (nNonce >= 0xffff0000) + break; + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != chainActive.Tip()) + break; + + // Update nTime every few seconds + UpdateTime(*pblock, pindexPrev); + if (Params().AllowMinDifficultyBlocks()) + { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); + } } } - } } + } catch (boost::thread_interrupted) { LogPrintf("BitcoinMiner terminated\n"); @@ -577,4 +580,4 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } -#endif +#endif // ENABLE_WALLET -- cgit v1.2.3 From df852d2bcc6573a3fcb3e59f82f7ea4dfa11290e Mon Sep 17 00:00:00 2001 From: jtimon Date: Mon, 10 Mar 2014 08:46:53 -0700 Subject: Refactor proof of work related functions out of main --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 63ce12506..2a4f8cfa5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -9,6 +9,7 @@ #include "hash.h" #include "main.h" #include "net.h" +#include "pow.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif -- cgit v1.2.3 From 2a72d4591f5adf25fcb4d0433b390ba6c37f57a9 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 11 Jul 2012 18:52:41 +0000 Subject: JSON-RPC method: prioritisetransaction Accepts the transaction into mined blocks at a higher (or lower) priority --- src/miner.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 19b469435..69e53756e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -3,6 +3,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + #include "miner.h" #include "core.h" @@ -186,6 +188,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority = tx.ComputePriority(dPriority, nTxSize); + uint256 hash = tx.GetHash(); + mempool.ApplyDeltas(hash, dPriority, nTotalIn); + CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); if (porphan) @@ -227,10 +232,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; // Skip free transactions if we're past the minimum block size: - if (fSortedByFee && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + const uint256& hash = tx.GetHash(); + double dPriorityDelta = 0; + int64_t nFeeDelta = 0; + mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); + if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; - // Prioritize by fee once past the priority size or we run out of high-priority + // Prioritise by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) @@ -257,7 +266,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; CTxUndo txundo; - const uint256& hash = tx.GetHash(); UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1); // Added -- cgit v1.2.3 From 13fc83c77bb9108c00dd7709ce17719edb763273 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 3 Jul 2014 14:25:32 -0400 Subject: Move fee policy out of core --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/miner.cpp') diff --git a/src/miner.cpp b/src/miner.cpp index 69e53756e..17918a128 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -236,7 +236,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) double dPriorityDelta = 0; int64_t nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritise by fee once past the priority size or we run out of high-priority -- cgit v1.2.3