diff options
56 files changed, 1093 insertions, 812 deletions
@@ -15,7 +15,7 @@ out collectively by the network. Bitcoin is also the name of the open source software which enables the use of this currency. For more information, as well as an immediately useable, binary version of -the Bitcoin client sofware, see http://www.bitcoin.org. +the Bitcoin client software, see http://www.bitcoin.org. License ------- diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index e2dab18abf..13c9d4cf24 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -157,6 +157,7 @@ HEADERS += src/qt/bitcoingui.h \ src/serialize.h \ src/core.h \ src/main.h \ + src/miner.h \ src/net.h \ src/key.h \ src/db.h \ @@ -240,6 +241,7 @@ SOURCES += src/qt/bitcoin.cpp \ src/core.cpp \ src/main.cpp \ src/init.cpp \ + src/miner.cpp \ src/net.cpp \ src/bloom.cpp \ src/checkpoints.cpp \ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index bc23cf5507..be18f9ae83 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -74,7 +74,7 @@ bool AppInit(int argc, char* argv[]) int ret = CommandLineRPC(argc, argv); exit(ret); } -#if !defined(WIN32) +#ifndef WIN32 fDaemon = GetBoolArg("-daemon", false); if (fDaemon) { diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 11fac42213..7a3e6560ab 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -414,7 +414,7 @@ int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto) int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet) { int nLen = 0; - loop + while (true) { string str; std::getline(stream, str); diff --git a/src/compat.h b/src/compat.h index 706221692b..4e98b46c1c 100644 --- a/src/compat.h +++ b/src/compat.h @@ -3,7 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef _BITCOIN_COMPAT_H -#define _BITCOIN_COMPAT_H 1 +#define _BITCOIN_COMPAT_H #ifdef WIN32 #define _WIN32_WINNT 0x0501 @@ -13,7 +13,6 @@ #endif #define FD_SETSIZE 1024 // max number of fds in fd_set #include <winsock2.h> -#include <mswsock.h> #include <ws2tcpip.h> #else #include <sys/types.h> @@ -26,12 +25,11 @@ #include <ifaddrs.h> #endif -typedef u_int SOCKET; #ifdef WIN32 #define MSG_NOSIGNAL 0 #define MSG_DONTWAIT 0 -typedef int socklen_t; #else +typedef u_int SOCKET; #include "errno.h" #define WSAGetLastError() errno #define WSAEINVAL EINVAL diff --git a/src/init.cpp b/src/init.cpp index c5a8cc9fbe..49d6e1fde4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -12,6 +12,7 @@ #include "bitcoinrpc.h" #include "net.h" #include "util.h" +#include "miner.h" #include "ui_interface.h" #include "checkpoints.h" @@ -29,6 +30,7 @@ using namespace std; using namespace boost; +std::string strWalletFile; CWallet* pwalletMain; CClientUIInterface uiInterface; @@ -169,6 +171,7 @@ std::string HelpMessage() strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n"; strUsage += " -gen " + _("Generate coins (default: 0)") + "\n"; strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n"; + strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n"; strUsage += " -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n"; strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n"; strUsage += " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n"; @@ -493,10 +496,16 @@ bool AppInit2(boost::thread_group& threadGroup) InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); } + strWalletFile = GetArg("-wallet", "wallet.dat"); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log std::string strDataDir = GetDataDir().string(); + // Wallet file must be a plain filename without a directory + if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) + return InitError(strprintf(_("Wallet %s resides outside data directory %s\n"), strWalletFile.c_str(), strDataDir.c_str())); + // Make sure only a single Bitcoin process is using the data directory. boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. @@ -555,13 +564,13 @@ bool AppInit2(boost::thread_group& threadGroup) if (GetBoolArg("-salvagewallet", false)) { // Recover readable keypairs: - if (!CWalletDB::Recover(bitdb, "wallet.dat", true)) + if (!CWalletDB::Recover(bitdb, strWalletFile, true)) return false; } - if (filesystem::exists(GetDataDir() / "wallet.dat")) + if (filesystem::exists(GetDataDir() / strWalletFile)) { - CDBEnv::VerifyResult r = bitdb.Verify("wallet.dat", CWalletDB::Recover); + CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!" @@ -839,7 +848,7 @@ bool AppInit2(boost::thread_group& threadGroup) nStart = GetTimeMillis(); bool fFirstRun = true; - pwalletMain = new CWallet("wallet.dat"); + pwalletMain = new CWallet(strWalletFile); DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); if (nLoadWalletRet != DB_LOAD_OK) { @@ -904,7 +913,7 @@ bool AppInit2(boost::thread_group& threadGroup) pindexRescan = pindexGenesisBlock; else { - CWalletDB walletdb("wallet.dat"); + CWalletDB walletdb(strWalletFile); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); diff --git a/src/init.h b/src/init.h index 5927670c83..a4d5a67252 100644 --- a/src/init.h +++ b/src/init.h @@ -7,6 +7,7 @@ #include "wallet.h" +extern std::string strWalletFile; extern CWallet* pwalletMain; void StartShutdown(); diff --git a/src/leveldb/AUTHORS b/src/leveldb/AUTHORS index 27a9407e52..fc40194ab9 100644 --- a/src/leveldb/AUTHORS +++ b/src/leveldb/AUTHORS @@ -6,3 +6,6 @@ Google Inc. # Initial version authors: Jeffrey Dean <jeff@google.com> Sanjay Ghemawat <sanjay@google.com> + +# Partial list of contributors: +Kevin Regan <kevin.d.regan@gmail.com> diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile index 42c4952fec..38b9bf7729 100644 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -42,6 +42,7 @@ TESTS = \ env_test \ filename_test \ filter_block_test \ + issue178_test \ log_test \ memenv_test \ skiplist_test \ @@ -69,7 +70,7 @@ SHARED = $(SHARED1) else # Update db.h if you change these. SHARED_MAJOR = 1 -SHARED_MINOR = 9 +SHARED_MINOR = 12 SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) SHARED2 = $(SHARED1).$(SHARED_MAJOR) SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) @@ -146,6 +147,9 @@ filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc index c9de169f29..af02467b33 100644 --- a/src/leveldb/db/db_impl.cc +++ b/src/leveldb/db/db_impl.cc @@ -35,6 +35,8 @@ namespace leveldb { +const int kNumNonTableCacheFiles = 10; + // Information kept for every waiting writer struct DBImpl::Writer { Status status; @@ -92,9 +94,9 @@ Options SanitizeOptions(const std::string& dbname, Options result = src; result.comparator = icmp; result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; - ClipToRange(&result.max_open_files, 20, 50000); - ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); - ClipToRange(&result.block_size, 1<<10, 4<<20); + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); if (result.info_log == NULL) { // Open a log file in the same directory as the db src.env->CreateDir(dbname); // In case it does not exist @@ -130,12 +132,13 @@ DBImpl::DBImpl(const Options& options, const std::string& dbname) log_(NULL), tmp_batch_(new WriteBatch), bg_compaction_scheduled_(false), - manual_compaction_(NULL) { + manual_compaction_(NULL), + consecutive_compaction_errors_(0) { mem_->Ref(); has_imm_.Release_Store(NULL); // Reserve ten files or so for other uses and give the rest to TableCache. - const int table_cache_size = options.max_open_files - 10; + const int table_cache_size = options.max_open_files - kNumNonTableCacheFiles; table_cache_ = new TableCache(dbname_, &options_, table_cache_size); versions_ = new VersionSet(dbname_, &options_, table_cache_, @@ -310,16 +313,24 @@ Status DBImpl::Recover(VersionEdit* edit) { if (!s.ok()) { return s; } + std::set<uint64_t> expected; + versions_->AddLiveFiles(&expected); uint64_t number; FileType type; std::vector<uint64_t> logs; for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) - && type == kLogFile - && ((number >= min_log) || (number == prev_log))) { + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) logs.push_back(number); } } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast<int>(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } // Recover in the order in which the logs were generated std::sort(logs.begin(), logs.end()); @@ -611,6 +622,7 @@ void DBImpl::BackgroundCall() { Status s = BackgroundCompaction(); if (s.ok()) { // Success + consecutive_compaction_errors_ = 0; } else if (shutting_down_.Acquire_Load()) { // Error most likely due to shutdown; do not wait } else { @@ -622,7 +634,12 @@ void DBImpl::BackgroundCall() { Log(options_.info_log, "Waiting after background compaction error: %s", s.ToString().c_str()); mutex_.Unlock(); - env_->SleepForMicroseconds(1000000); + ++consecutive_compaction_errors_; + int seconds_to_sleep = 1; + for (int i = 0; i < 3 && i < consecutive_compaction_errors_ - 1; ++i) { + seconds_to_sleep *= 2; + } + env_->SleepForMicroseconds(seconds_to_sleep * 1000000); mutex_.Lock(); } } @@ -805,6 +822,9 @@ Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, (unsigned long long) output_number, (unsigned long long) current_entries, (unsigned long long) current_bytes); + + // rate-limit compaction file creation with a 100ms pause + env_->SleepForMicroseconds(100000); } } return s; @@ -1268,10 +1288,11 @@ Status DBImpl::MakeRoomForWrite(bool force) { } else if (imm_ != NULL) { // We have filled up the current memtable, but the previous // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); bg_cv_.Wait(); } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { // There are too many level-0 files. - Log(options_.info_log, "waiting...\n"); + Log(options_.info_log, "Too many L0 files; waiting...\n"); bg_cv_.Wait(); } else { // Attempt to switch to a new memtable and trigger compaction of old diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h index bd29dd8055..3c8d711ae0 100644 --- a/src/leveldb/db/db_impl.h +++ b/src/leveldb/db/db_impl.h @@ -163,6 +163,7 @@ class DBImpl : public DB { // Have we encountered a background error in paranoid mode? Status bg_error_; + int consecutive_compaction_errors_; // Per level compaction stats. stats_[level] stores the stats for // compactions that produced data for the specified "level". diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc index 684ea3bdbc..49aae04dbd 100644 --- a/src/leveldb/db/db_test.cc +++ b/src/leveldb/db/db_test.cc @@ -33,8 +33,11 @@ class AtomicCounter { public: AtomicCounter() : count_(0) { } void Increment() { + IncrementBy(1); + } + void IncrementBy(int count) { MutexLock l(&mu_); - count_++; + count_ += count; } int Read() { MutexLock l(&mu_); @@ -45,6 +48,10 @@ class AtomicCounter { count_ = 0; } }; + +void DelayMilliseconds(int millis) { + Env::Default()->SleepForMicroseconds(millis * 1000); +} } // Special Env used to delay background operations @@ -69,6 +76,7 @@ class SpecialEnv : public EnvWrapper { AtomicCounter random_read_counter_; AtomicCounter sleep_counter_; + AtomicCounter sleep_time_counter_; explicit SpecialEnv(Env* base) : EnvWrapper(base) { delay_sstable_sync_.Release_Store(NULL); @@ -103,7 +111,7 @@ class SpecialEnv : public EnvWrapper { Status Flush() { return base_->Flush(); } Status Sync() { while (env_->delay_sstable_sync_.Acquire_Load() != NULL) { - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } return base_->Sync(); } @@ -174,8 +182,9 @@ class SpecialEnv : public EnvWrapper { virtual void SleepForMicroseconds(int micros) { sleep_counter_.Increment(); - target()->SleepForMicroseconds(micros); + sleep_time_counter_.IncrementBy(micros); } + }; class DBTest { @@ -461,6 +470,20 @@ class DBTest { } return result; } + + bool DeleteAnSSTFile() { + std::vector<std::string> filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); + return true; + } + } + return false; + } }; TEST(DBTest, Empty) { @@ -611,7 +634,7 @@ TEST(DBTest, GetEncountersEmptyLevel) { } // Step 4: Wait for compaction to finish - env_->SleepForMicroseconds(1000000); + DelayMilliseconds(1000); ASSERT_EQ(NumTableFilesAtLevel(0), 0); } while (ChangeOptions()); @@ -1295,7 +1318,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_a) { Reopen(); Reopen(); ASSERT_EQ("(a->v)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish ASSERT_EQ("(a->v)", Contents()); } @@ -1311,7 +1334,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_b) { Put("",""); Reopen(); Put("",""); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish Reopen(); Put("d","dv"); Reopen(); @@ -1321,7 +1344,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_b) { Delete("b"); Reopen(); ASSERT_EQ("(->)(c->cv)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish ASSERT_EQ("(->)(c->cv)", Contents()); } @@ -1506,6 +1529,30 @@ TEST(DBTest, NoSpace) { ASSERT_GE(env_->sleep_counter_.Read(), 5); } +TEST(DBTest, ExponentialBackoff) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + env_->non_writable_.Release_Store(env_); // Force errors for new files + env_->sleep_counter_.Reset(); + env_->sleep_time_counter_.Reset(); + for (int i = 0; i < 5; i++) { + dbfull()->TEST_CompactRange(2, NULL, NULL); + } + env_->non_writable_.Release_Store(NULL); + + // Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_GE(env_->sleep_counter_.Read(), 5); + ASSERT_LT(env_->sleep_counter_.Read(), 10); + ASSERT_GE(env_->sleep_time_counter_.Read(), 10e6); +} + TEST(DBTest, NonWritableFileSystem) { Options options = CurrentOptions(); options.write_buffer_size = 1000; @@ -1519,7 +1566,7 @@ TEST(DBTest, NonWritableFileSystem) { fprintf(stderr, "iter %d; errors %d\n", i, errors); if (!Put("foo", big).ok()) { errors++; - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } } ASSERT_GT(errors, 0); @@ -1567,6 +1614,24 @@ TEST(DBTest, ManifestWriteError) { } } +TEST(DBTest, MissingSSTFile) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + + Close(); + ASSERT_TRUE(DeleteAnSSTFile()); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) + << s.ToString(); +} + TEST(DBTest, FilesDeletedAfterCompaction) { ASSERT_OK(Put("foo", "v2")); Compact("a", "z"); @@ -1711,13 +1776,13 @@ TEST(DBTest, MultiThreaded) { } // Let them run for a while - env_->SleepForMicroseconds(kTestSeconds * 1000000); + DelayMilliseconds(kTestSeconds * 1000); // Stop the threads and wait for them to finish mt.stop.Release_Store(&mt); for (int id = 0; id < kNumThreads; id++) { while (mt.thread_done[id].Acquire_Load() == NULL) { - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } } } while (ChangeOptions()); diff --git a/src/leveldb/db/dbformat.cc b/src/leveldb/db/dbformat.cc index 28e11b398d..20a7ca4462 100644 --- a/src/leveldb/db/dbformat.cc +++ b/src/leveldb/db/dbformat.cc @@ -26,7 +26,7 @@ std::string ParsedInternalKey::DebugString() const { (unsigned long long) sequence, int(type)); std::string result = "'"; - result += user_key.ToString(); + result += EscapeString(user_key.ToString()); result += buf; return result; } diff --git a/src/leveldb/db/filename_test.cc b/src/leveldb/db/filename_test.cc index 47353d6c9a..5a26da4728 100644 --- a/src/leveldb/db/filename_test.cc +++ b/src/leveldb/db/filename_test.cc @@ -70,7 +70,7 @@ TEST(FileNameTest, Parse) { for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { std::string f = errors[i]; ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; - }; + } } TEST(FileNameTest, Construction) { diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index 7d0a5de2b9..4fd1ddef21 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -1331,14 +1331,19 @@ Compaction* VersionSet::CompactRange( } // Avoid compacting too much in one shot in case the range is large. - const uint64_t limit = MaxFileSizeForLevel(level); - uint64_t total = 0; - for (size_t i = 0; i < inputs.size(); i++) { - uint64_t s = inputs[i]->file_size; - total += s; - if (total >= limit) { - inputs.resize(i + 1); - break; + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } } } diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h index 29d3674479..da8b11a8c0 100644 --- a/src/leveldb/include/leveldb/db.h +++ b/src/leveldb/include/leveldb/db.h @@ -14,7 +14,7 @@ namespace leveldb { // Update Makefile if you change these static const int kMajorVersion = 1; -static const int kMinorVersion = 9; +static const int kMinorVersion = 12; struct Options; struct ReadOptions; diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 99c1d8e346..1b0f060a19 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -109,12 +109,10 @@ void CondVar::Signal() { void CondVar::SignalAll() { wait_mtx_.Lock(); - for(long i = 0; i < waiting_; ++i) { - ::ReleaseSemaphore(sem1_, 1, NULL); - while(waiting_ > 0) { - --waiting_; - ::WaitForSingleObject(sem2_, INFINITE); - } + ::ReleaseSemaphore(sem1_, waiting_, NULL); + while(waiting_ > 0) { + --waiting_; + ::WaitForSingleObject(sem2_, INFINITE); } wait_mtx_.Unlock(); } diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc index ab83c1112c..79ea9d9ee5 100644 --- a/src/leveldb/table/block.cc +++ b/src/leveldb/table/block.cc @@ -16,7 +16,7 @@ namespace leveldb { inline uint32_t Block::NumRestarts() const { - assert(size_ >= 2*sizeof(uint32_t)); + assert(size_ >= sizeof(uint32_t)); return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); } @@ -27,11 +27,12 @@ Block::Block(const BlockContents& contents) if (size_ < sizeof(uint32_t)) { size_ = 0; // Error marker } else { - restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); - if (restart_offset_ > size_ - sizeof(uint32_t)) { - // The size is too small for NumRestarts() and therefore - // restart_offset_ wrapped around. + size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); } } } @@ -253,7 +254,7 @@ class Block::Iter : public Iterator { }; Iterator* Block::NewIterator(const Comparator* cmp) { - if (size_ < 2*sizeof(uint32_t)) { + if (size_ < sizeof(uint32_t)) { return NewErrorIterator(Status::Corruption("bad block contents")); } const uint32_t num_restarts = NumRestarts(); diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc index dbd6d3a1bf..71c1756e5f 100644 --- a/src/leveldb/table/table.cc +++ b/src/leveldb/table/table.cc @@ -228,7 +228,6 @@ Status Table::InternalGet(const ReadOptions& options, const Slice& k, !filter->KeyMayMatch(handle.offset(), k)) { // Not found } else { - Slice handle = iiter->value(); Iterator* block_iter = BlockReader(this, options, iiter->value()); block_iter->Seek(k); if (block_iter->Valid()) { diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc index 57cea25334..c723bf84cf 100644 --- a/src/leveldb/table/table_test.cc +++ b/src/leveldb/table/table_test.cc @@ -644,6 +644,36 @@ class Harness { Constructor* constructor_; }; +// Test empty table/block. +TEST(Harness, Empty) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Test(&rnd); + } +} + +// Special test for a block with no restart entries. The C++ leveldb +// code never generates such blocks, but the Java version of leveldb +// seems to. +TEST(Harness, ZeroRestartPointsInBlock) { + char data[sizeof(uint32_t)]; + memset(data, 0, sizeof(data)); + BlockContents contents; + contents.data = Slice(data, sizeof(data)); + contents.cachable = false; + contents.heap_allocated = false; + Block block(contents); + Iterator* iter = block.NewIterator(BytewiseComparator()); + iter->SeekToFirst(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + ASSERT_TRUE(!iter->Valid()); + iter->Seek("foo"); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + // Test the empty key TEST(Harness, SimpleEmptyKey) { for (int i = 0; i < kNumTestArgs; i++) { diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc index 24f1f63f4f..8b197bc02a 100644 --- a/src/leveldb/util/cache.cc +++ b/src/leveldb/util/cache.cc @@ -116,7 +116,6 @@ class HandleTable { LRUHandle* h = list_[i]; while (h != NULL) { LRUHandle* next = h->next_hash; - Slice key = h->key(); uint32_t hash = h->hash; LRUHandle** ptr = &new_list[hash & (new_length - 1)]; h->next_hash = *ptr; @@ -160,7 +159,6 @@ class LRUCache { // mutex_ protects the following state. port::Mutex mutex_; size_t usage_; - uint64_t last_id_; // Dummy head of LRU list. // lru.prev is newest entry, lru.next is oldest entry. @@ -170,8 +168,7 @@ class LRUCache { }; LRUCache::LRUCache() - : usage_(0), - last_id_(0) { + : usage_(0) { // Make empty circular linked list lru_.next = &lru_; lru_.prev = &lru_; diff --git a/src/leveldb/util/coding_test.cc b/src/leveldb/util/coding_test.cc index 2c52b17b60..fb5726e335 100644 --- a/src/leveldb/util/coding_test.cc +++ b/src/leveldb/util/coding_test.cc @@ -109,7 +109,7 @@ TEST(Coding, Varint64) { values.push_back(power); values.push_back(power-1); values.push_back(power+1); - }; + } std::string s; for (int i = 0; i < values.size(); i++) { diff --git a/src/leveldb/util/comparator.cc b/src/leveldb/util/comparator.cc index 4b7b5724ef..6cc319242e 100644 --- a/src/leveldb/util/comparator.cc +++ b/src/leveldb/util/comparator.cc @@ -66,7 +66,7 @@ class BytewiseComparatorImpl : public Comparator { }; } // namespace -static port::OnceType once = LEVELDB_ONCE_INIT; +static port::OnceType once_comparator = LEVELDB_ONCE_INIT; static const Comparator* bytewise; static void InitModule() { @@ -74,7 +74,7 @@ static void InitModule() { } const Comparator* BytewiseComparator() { - port::InitOnce(&once, InitModule); + port::InitOnce(&once_comparator, InitModule); return bytewise; } diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc index db81f56d11..6badfdc230 100644 --- a/src/leveldb/util/env_posix.cc +++ b/src/leveldb/util/env_posix.cc @@ -386,7 +386,7 @@ class PosixEnv : public Env { PosixEnv(); virtual ~PosixEnv() { fprintf(stderr, "Destroying Env::Default()\n"); - exit(1); + abort(); } virtual Status NewSequentialFile(const std::string& fname, @@ -467,7 +467,7 @@ class PosixEnv : public Env { result = IOError(fname, errno); } return result; - }; + } virtual Status CreateDir(const std::string& name) { Status result; @@ -475,7 +475,7 @@ class PosixEnv : public Env { result = IOError(name, errno); } return result; - }; + } virtual Status DeleteDir(const std::string& name) { Status result; @@ -483,7 +483,7 @@ class PosixEnv : public Env { result = IOError(name, errno); } return result; - }; + } virtual Status GetFileSize(const std::string& fname, uint64_t* size) { Status s; @@ -589,7 +589,7 @@ class PosixEnv : public Env { void PthreadCall(const char* label, int result) { if (result != 0) { fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - exit(1); + abort(); } } diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc index ba1818082d..07cf022060 100644 --- a/src/leveldb/util/hash.cc +++ b/src/leveldb/util/hash.cc @@ -6,6 +6,13 @@ #include "util/coding.h" #include "util/hash.h" +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED do { } while (0) +#endif + namespace leveldb { uint32_t Hash(const char* data, size_t n, uint32_t seed) { @@ -28,10 +35,10 @@ uint32_t Hash(const char* data, size_t n, uint32_t seed) { switch (limit - data) { case 3: h += data[2] << 16; - // fall through + FALLTHROUGH_INTENDED; case 2: h += data[1] << 8; - // fall through + FALLTHROUGH_INTENDED; case 1: h += data[0]; h *= m; diff --git a/src/main.cpp b/src/main.cpp index c8b4876c3e..50cff7f51d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1244,7 +1244,7 @@ uint256 static GetOrphanRoot(const CBlockHeader* pblock) return pblock->GetHash(); } -int64 static GetBlockValue(int nHeight, int64 nFees) +int64 GetBlockValue(int nHeight, int64 nFees) { int64 nSubsidy = 50 * COIN; @@ -1284,7 +1284,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) return bnResult.GetCompact(); } -unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact(); @@ -4124,662 +4124,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) - - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// 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]; -} - -// -// 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. -// -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 - nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); - - // 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 nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } - if ((nNonce & 0xfff) == 0) - boost::this_thread::interruption_point(); - } -} - -// Some explaining would be appreciated -class COrphan -{ -public: - CTransaction* ptx; - set<uint256> setDependsOn; - double dPriority; - double dFeePerKb; - - COrphan(CTransaction* ptxIn) - { - ptx = ptxIn; - dPriority = dFeePerKb = 0; - } - - void print() const - { - printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", - ptx->GetHash().ToString().c_str(), dPriority, dFeePerKb); - BOOST_FOREACH(uint256 hash, setDependsOn) - printf(" setDependsOn %s\n", hash.ToString().c_str()); - } -}; - - -uint64 nLastBlockTx = 0; -uint64 nLastBlockSize = 0; - -// We want to sort transactions by priority and fee, so: -typedef boost::tuple<double, double, CTransaction*> TxPriority; -class TxPriorityCompare -{ - bool byFee; -public: - TxPriorityCompare(bool _byFee) : byFee(_byFee) { } - bool operator()(const TxPriority& a, const TxPriority& b) - { - if (byFee) - { - if (a.get<1>() == b.get<1>()) - return a.get<0>() < b.get<0>(); - return a.get<1>() < b.get<1>(); - } - else - { - if (a.get<0>() == b.get<0>()) - return a.get<1>() < b.get<1>(); - return a.get<0>() < b.get<0>(); - } - } -}; - -CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) -{ - // Create new block - auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); - if(!pblocktemplate.get()) - return NULL; - CBlock *pblock = &pblocktemplate->block; // pointer for convenience - - // Create coinbase tx - CTransaction txNew; - txNew.vin.resize(1); - txNew.vin[0].prevout.SetNull(); - txNew.vout.resize(1); - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG; - - // Add our coinbase tx as first transaction - pblock->vtx.push_back(txNew); - pblocktemplate->vTxFees.push_back(-1); // updated at end - pblocktemplate->vTxSigOps.push_back(-1); // updated at end - - // Largest block you're willing to create: - unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); - // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - - // How much of the block should be dedicated to high-priority transactions, - // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); - nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); - - // Minimum block size you want to create; block will be filled with free transactions - // until there are no more or the block reaches this size: - unsigned int nBlockMinSize = GetArg("-blockminsize", 0); - nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - - // Collect memory pool transactions into the block - int64 nFees = 0; - { - LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = pindexBest; - CCoinsViewCache view(*pcoinsTip, true); - - // Priority order to process transactions - list<COrphan> vOrphan; // list memory doesn't move - map<uint256, vector<COrphan*> > mapDependers; - bool fPrintPriority = GetBoolArg("-printpriority", false); - - // This vector will be sorted into a priority queue: - vector<TxPriority> vecPriority; - vecPriority.reserve(mempool.mapTx.size()); - for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) - { - CTransaction& tx = (*mi).second; - if (tx.IsCoinBase() || !IsFinalTx(tx)) - continue; - - COrphan* porphan = NULL; - double dPriority = 0; - int64 nTotalIn = 0; - bool fMissingInputs = false; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - // Read prev transaction - if (!view.HaveCoins(txin.prevout.hash)) - { - // This should never happen; all transactions in the memory - // pool should connect to either transactions in the chain - // or other transactions in the memory pool. - if (!mempool.mapTx.count(txin.prevout.hash)) - { - printf("ERROR: mempool transaction missing input\n"); - if (fDebug) assert("mempool transaction missing input" == 0); - fMissingInputs = true; - if (porphan) - vOrphan.pop_back(); - break; - } - - // Has to wait for dependencies - if (!porphan) - { - // Use list for automatic deletion - vOrphan.push_back(COrphan(&tx)); - porphan = &vOrphan.back(); - } - mapDependers[txin.prevout.hash].push_back(porphan); - porphan->setDependsOn.insert(txin.prevout.hash); - nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; - continue; - } - const CCoins &coins = view.GetCoins(txin.prevout.hash); - - int64 nValueIn = coins.vout[txin.prevout.n].nValue; - nTotalIn += nValueIn; - - int nConf = pindexPrev->nHeight - coins.nHeight + 1; - - dPriority += (double)nValueIn * nConf; - } - if (fMissingInputs) continue; - - // Priority is sum(valuein * age) / txsize - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - 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-GetValueOut(tx)) / (double(nTxSize)/1000.0); - - if (porphan) - { - porphan->dPriority = dPriority; - porphan->dFeePerKb = dFeePerKb; - } - else - vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second)); - } - - // Collect transactions into block - uint64 nBlockSize = 1000; - uint64 nBlockTx = 0; - int nBlockSigOps = 100; - bool fSortedByFee = (nBlockPrioritySize <= 0); - - TxPriorityCompare comparer(fSortedByFee); - std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); - - while (!vecPriority.empty()) - { - // Take highest priority transaction off the priority queue: - double dPriority = vecPriority.front().get<0>(); - double dFeePerKb = vecPriority.front().get<1>(); - CTransaction& tx = *(vecPriority.front().get<2>()); - - std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); - vecPriority.pop_back(); - - // Size limits - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - if (nBlockSize + nTxSize >= nBlockMaxSize) - continue; - - // Legacy limits on sigOps: - unsigned int nTxSigOps = GetLegacySigOpCount(tx); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) - continue; - - // Skip free transactions if we're past the minimum block size: - if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) - continue; - - // Prioritize by fee once past the priority size or we run out of high-priority - // transactions: - if (!fSortedByFee && - ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) - { - fSortedByFee = true; - comparer = TxPriorityCompare(fSortedByFee); - std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); - } - - if (!view.HaveInputs(tx)) - continue; - - int64 nTxFees = view.GetValueIn(tx)-GetValueOut(tx); - - nTxSigOps += GetP2SHSigOpCount(tx, view); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) - continue; - - CValidationState state; - if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH)) - continue; - - CTxUndo txundo; - uint256 hash = tx.GetHash(); - UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash); - - // Added - pblock->vtx.push_back(tx); - pblocktemplate->vTxFees.push_back(nTxFees); - pblocktemplate->vTxSigOps.push_back(nTxSigOps); - nBlockSize += nTxSize; - ++nBlockTx; - nBlockSigOps += nTxSigOps; - nFees += nTxFees; - - if (fPrintPriority) - { - printf("priority %.1f feeperkb %.1f txid %s\n", - dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); - } - - // Add transactions that depend on this one to the priority queue - if (mapDependers.count(hash)) - { - BOOST_FOREACH(COrphan* porphan, mapDependers[hash]) - { - if (!porphan->setDependsOn.empty()) - { - porphan->setDependsOn.erase(hash); - if (porphan->setDependsOn.empty()) - { - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); - std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); - } - } - } - } - } - - nLastBlockTx = nBlockTx; - nLastBlockSize = nBlockSize; - printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); - - pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); - pblocktemplate->vTxFees[0] = -nFees; - - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - 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); - indexDummy.pprev = pindexPrev; - indexDummy.nHeight = pindexPrev->nHeight + 1; - CCoinsViewCache viewNew(*pcoinsTip, true); - CValidationState state; - if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) - throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); - } - - return pblocktemplate.release(); -} - - -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) -{ - // Update nExtraNonce - static uint256 hashPrevBlock; - if (hashPrevBlock != pblock->hashPrevBlock) - { - nExtraNonce = 0; - hashPrevBlock = pblock->hashPrevBlock; - } - ++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; - assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); - - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); -} - - -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); -} - - -bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) -{ - uint256 hash = pblock->GetHash(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - - if (hash > hashTarget) - return false; - - //// debug print - printf("BitcoinMiner:\n"); - printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); - pblock->print(); - printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); - - // Found a solution - { - LOCK(cs_main); - if (pblock->hashPrevBlock != hashBestChain) - 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; - } - - // 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; -} - -void static BitcoinMiner(CWallet *pwallet) -{ - printf("BitcoinMiner started\n"); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("bitcoin-miner"); - - // Each thread has its own key and counter - CReserveKey reservekey(pwallet); - unsigned int nExtraNonce = 0; - - try { loop { - if (Params().NetworkID() != CChainParams::REGTEST) { - // 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 = nTransactionsUpdated; - CBlockIndex* pindexPrev = pindexBest; - - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(reservekey)); - if (!pblocktemplate.get()) - return; - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - printf("Running BitcoinMiner with %"PRIszu" 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 nStart = GetTime(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - uint256 hashbuf[2]; - uint256& hash = *alignup<16>(hashbuf); - loop - { - unsigned int nHashesDone = 0; - unsigned int nNonceFound; - - // Crypto++ SHA256 - nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1, - (char*)&hash, nHashesDone); - - // Check if something found - if (nNonceFound != (unsigned int) -1) - { - 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); - assert(hash == pblock->GetHash()); - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock, *pwalletMain, 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) - throw boost::thread_interrupted(); - - break; - } - } - - // Meter hashes/sec - static int64 nHashCounter; - if (nHPSTimerStart == 0) - { - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - } - else - nHashCounter += nHashesDone; - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - static CCriticalSection cs; - { - LOCK(cs); - if (GetTimeMillis() - nHPSTimerStart > 4000) - { - dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = GetTimeMillis(); - nHashCounter = 0; - static int64 nLogTime; - if (GetTime() - nLogTime > 30 * 60) - { - nLogTime = GetTime(); - printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); - } - } - } - } - - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) - break; - if (nBlockNonce >= 0xffff0000) - break; - if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != pindexBest) - break; - - // Update nTime every few seconds - UpdateTime(*pblock, pindexPrev); - nBlockTime = ByteReverse(pblock->nTime); - if (TestNet()) - { - // Changing pblock->nTime can change work required on testnet: - nBlockBits = ByteReverse(pblock->nBits); - hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - } - } - } } - catch (boost::thread_interrupted) - { - printf("BitcoinMiner terminated\n"); - throw; - } -} - -void GenerateBitcoins(bool fGenerate, CWallet* pwallet) -{ - static boost::thread_group* minerThreads = NULL; - - int nThreads = GetArg("-genproclimit", -1); - if (nThreads < 0) { - if (Params().NetworkID() == CChainParams::REGTEST) - nThreads = 1; - else - nThreads = boost::thread::hardware_concurrency(); - } - - if (minerThreads != NULL) - { - minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; - } - - if (nThreads == 0 || !fGenerate) - return; - - minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); -} - - - class CMainCleanup { public: diff --git a/src/main.h b/src/main.h index 8ad2437c63..cb0ee1aaa8 100644 --- a/src/main.h +++ b/src/main.h @@ -159,16 +159,6 @@ bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); -/** Run the miner threads */ -void GenerateBitcoins(bool fGenerate, CWallet* pwallet); -/** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(CReserveKey& reservekey); -/** Modify the extranonce in a block */ -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); -/** Do mining precalculation */ -void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); -/** Check mined block */ -bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& 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 */ @@ -185,6 +175,8 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew); /** Find the best known block, and make it the tip of the block chain */ bool ConnectBestBlock(CValidationState &state); +int64 GetBlockValue(int nHeight, int64 nFees); +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); @@ -318,7 +310,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach std::vector<CScriptCheck> *pvChecks = NULL); // Apply the effects of this transaction on the UTXO set represented by view -bool UpdateCoins(const CTransaction& tx, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash); +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash); // Context-independent validity checks bool CheckTransaction(const CTransaction& tx, CValidationState& state); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 26d541664e..51830f2342 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -75,6 +75,7 @@ OBJS= \ obj/keystore.o \ obj/core.o \ obj/main.o \ + obj/miner.o \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ diff --git a/src/makefile.mingw b/src/makefile.mingw index 002e36d3e2..464f69b1c9 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -83,6 +83,7 @@ OBJS= \ obj/keystore.o \ obj/core.o \ obj/main.o \ + obj/miner.o \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ diff --git a/src/makefile.osx b/src/makefile.osx index 269460c1ba..ee364f5c4a 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -86,6 +86,7 @@ OBJS= \ obj/keystore.o \ obj/core.o \ obj/main.o \ + obj/miner.o \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ diff --git a/src/makefile.unix b/src/makefile.unix index f17de05cb9..e00db09a33 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -125,6 +125,7 @@ OBJS= \ obj/keystore.o \ obj/core.o \ obj/main.o \ + obj/miner.o \ obj/net.o \ obj/protocol.o \ obj/bitcoinrpc.o \ diff --git a/src/miner.cpp b/src/miner.cpp new file mode 100644 index 0000000000..e50c0b576d --- /dev/null +++ b/src/miner.cpp @@ -0,0 +1,663 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "core.h" +#include "wallet.h" +#include "miner.h" +#include "main.h" + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// 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]; +} + +// +// 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. +// +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 + nNonce++; + SHA256Transform(phash1, pdata, pmidstate); + SHA256Transform(phash, phash1, pSHA256InitState); + + // 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 nothing found after trying for a while, return -1 + if ((nNonce & 0xffff) == 0) + { + nHashesDone = 0xffff+1; + return (unsigned int) -1; + } + if ((nNonce & 0xfff) == 0) + boost::this_thread::interruption_point(); + } +} + +// Some explaining would be appreciated +class COrphan +{ +public: + CTransaction* ptx; + set<uint256> setDependsOn; + double dPriority; + double dFeePerKb; + + COrphan(CTransaction* ptxIn) + { + ptx = ptxIn; + dPriority = dFeePerKb = 0; + } + + void print() const + { + printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", + ptx->GetHash().ToString().c_str(), dPriority, dFeePerKb); + BOOST_FOREACH(uint256 hash, setDependsOn) + printf(" setDependsOn %s\n", hash.ToString().c_str()); + } +}; + + +uint64 nLastBlockTx = 0; +uint64 nLastBlockSize = 0; + +// We want to sort transactions by priority and fee, so: +typedef boost::tuple<double, double, CTransaction*> TxPriority; +class TxPriorityCompare +{ + bool byFee; +public: + TxPriorityCompare(bool _byFee) : byFee(_byFee) { } + bool operator()(const TxPriority& a, const TxPriority& b) + { + if (byFee) + { + if (a.get<1>() == b.get<1>()) + return a.get<0>() < b.get<0>(); + return a.get<1>() < b.get<1>(); + } + else + { + if (a.get<0>() == b.get<0>()) + return a.get<1>() < b.get<1>(); + return a.get<0>() < b.get<0>(); + } + } +}; + +CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) +{ + // Create new block + auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); + if(!pblocktemplate.get()) + return NULL; + CBlock *pblock = &pblocktemplate->block; // pointer for convenience + + // Create coinbase tx + CTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vout.resize(1); + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG; + + // Add our coinbase tx as first transaction + pblock->vtx.push_back(txNew); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end + + // Largest block you're willing to create: + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); + // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + + // How much of the block should be dedicated to high-priority transactions, + // included regardless of the fees they pay + unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); + nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); + + // Minimum block size you want to create; block will be filled with free transactions + // until there are no more or the block reaches this size: + unsigned int nBlockMinSize = GetArg("-blockminsize", 0); + nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); + + // Collect memory pool transactions into the block + int64 nFees = 0; + { + LOCK2(cs_main, mempool.cs); + CBlockIndex* pindexPrev = pindexBest; + CCoinsViewCache view(*pcoinsTip, true); + + // Priority order to process transactions + list<COrphan> vOrphan; // list memory doesn't move + map<uint256, vector<COrphan*> > mapDependers; + bool fPrintPriority = GetBoolArg("-printpriority", false); + + // This vector will be sorted into a priority queue: + vector<TxPriority> vecPriority; + vecPriority.reserve(mempool.mapTx.size()); + for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) + { + CTransaction& tx = (*mi).second; + if (tx.IsCoinBase() || !IsFinalTx(tx)) + continue; + + COrphan* porphan = NULL; + double dPriority = 0; + int64 nTotalIn = 0; + bool fMissingInputs = false; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // Read prev transaction + if (!view.HaveCoins(txin.prevout.hash)) + { + // This should never happen; all transactions in the memory + // pool should connect to either transactions in the chain + // or other transactions in the memory pool. + if (!mempool.mapTx.count(txin.prevout.hash)) + { + printf("ERROR: mempool transaction missing input\n"); + if (fDebug) assert("mempool transaction missing input" == 0); + fMissingInputs = true; + if (porphan) + vOrphan.pop_back(); + break; + } + + // Has to wait for dependencies + if (!porphan) + { + // Use list for automatic deletion + vOrphan.push_back(COrphan(&tx)); + porphan = &vOrphan.back(); + } + mapDependers[txin.prevout.hash].push_back(porphan); + porphan->setDependsOn.insert(txin.prevout.hash); + nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; + continue; + } + const CCoins &coins = view.GetCoins(txin.prevout.hash); + + int64 nValueIn = coins.vout[txin.prevout.n].nValue; + nTotalIn += nValueIn; + + int nConf = pindexPrev->nHeight - coins.nHeight + 1; + + dPriority += (double)nValueIn * nConf; + } + if (fMissingInputs) continue; + + // Priority is sum(valuein * age) / txsize + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + 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-GetValueOut(tx)) / (double(nTxSize)/1000.0); + + if (porphan) + { + porphan->dPriority = dPriority; + porphan->dFeePerKb = dFeePerKb; + } + else + vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second)); + } + + // Collect transactions into block + uint64 nBlockSize = 1000; + uint64 nBlockTx = 0; + int nBlockSigOps = 100; + bool fSortedByFee = (nBlockPrioritySize <= 0); + + TxPriorityCompare comparer(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + + while (!vecPriority.empty()) + { + // Take highest priority transaction off the priority queue: + double dPriority = vecPriority.front().get<0>(); + double dFeePerKb = vecPriority.front().get<1>(); + CTransaction& tx = *(vecPriority.front().get<2>()); + + std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); + vecPriority.pop_back(); + + // Size limits + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + if (nBlockSize + nTxSize >= nBlockMaxSize) + continue; + + // Legacy limits on sigOps: + unsigned int nTxSigOps = GetLegacySigOpCount(tx); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + continue; + + // Skip free transactions if we're past the minimum block size: + if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + continue; + + // Prioritize by fee once past the priority size or we run out of high-priority + // transactions: + if (!fSortedByFee && + ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) + { + fSortedByFee = true; + comparer = TxPriorityCompare(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + } + + if (!view.HaveInputs(tx)) + continue; + + int64 nTxFees = view.GetValueIn(tx)-GetValueOut(tx); + + nTxSigOps += GetP2SHSigOpCount(tx, view); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + continue; + + CValidationState state; + if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH)) + continue; + + CTxUndo txundo; + uint256 hash = tx.GetHash(); + UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash); + + // Added + pblock->vtx.push_back(tx); + pblocktemplate->vTxFees.push_back(nTxFees); + pblocktemplate->vTxSigOps.push_back(nTxSigOps); + nBlockSize += nTxSize; + ++nBlockTx; + nBlockSigOps += nTxSigOps; + nFees += nTxFees; + + if (fPrintPriority) + { + printf("priority %.1f feeperkb %.1f txid %s\n", + dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); + } + + // Add transactions that depend on this one to the priority queue + if (mapDependers.count(hash)) + { + BOOST_FOREACH(COrphan* porphan, mapDependers[hash]) + { + if (!porphan->setDependsOn.empty()) + { + porphan->setDependsOn.erase(hash); + if (porphan->setDependsOn.empty()) + { + vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); + std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); + } + } + } + } + } + + nLastBlockTx = nBlockTx; + nLastBlockSize = nBlockSize; + printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); + + pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + pblocktemplate->vTxFees[0] = -nFees; + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + 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); + indexDummy.pprev = pindexPrev; + indexDummy.nHeight = pindexPrev->nHeight + 1; + CCoinsViewCache viewNew(*pcoinsTip, true); + CValidationState state; + if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) + throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); + } + + return pblocktemplate.release(); +} + + +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) +{ + // Update nExtraNonce + static uint256 hashPrevBlock; + if (hashPrevBlock != pblock->hashPrevBlock) + { + nExtraNonce = 0; + hashPrevBlock = pblock->hashPrevBlock; + } + ++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; + assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); + + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); +} + + +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); +} + + +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) +{ + uint256 hash = pblock->GetHash(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + if (hash > hashTarget) + return false; + + //// debug print + printf("BitcoinMiner:\n"); + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); + + // Found a solution + { + LOCK(cs_main); + if (pblock->hashPrevBlock != hashBestChain) + 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; + } + + // 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; +} + +void static BitcoinMiner(CWallet *pwallet) +{ + printf("BitcoinMiner started\n"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("bitcoin-miner"); + + // Each thread has its own key and counter + CReserveKey reservekey(pwallet); + unsigned int nExtraNonce = 0; + + try { while (true) { + if (Params().NetworkID() != CChainParams::REGTEST) { + // 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 = nTransactionsUpdated; + CBlockIndex* pindexPrev = pindexBest; + + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(reservekey)); + if (!pblocktemplate.get()) + return; + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + printf("Running BitcoinMiner with %"PRIszu" 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 nStart = GetTime(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashbuf[2]; + uint256& hash = *alignup<16>(hashbuf); + while (true) + { + unsigned int nHashesDone = 0; + unsigned int nNonceFound; + + // Crypto++ SHA256 + nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1, + (char*)&hash, nHashesDone); + + // Check if something found + if (nNonceFound != (unsigned int) -1) + { + 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); + assert(hash == pblock->GetHash()); + + SetThreadPriority(THREAD_PRIORITY_NORMAL); + 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) + throw boost::thread_interrupted(); + + break; + } + } + + // Meter hashes/sec + static int64 nHashCounter; + if (nHPSTimerStart == 0) + { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; + { + LOCK(cs); + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + static int64 nLogTime; + if (GetTime() - nLogTime > 30 * 60) + { + nLogTime = GetTime(); + printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); + } + } + } + } + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST) + break; + if (nBlockNonce >= 0xffff0000) + break; + if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != pindexBest) + break; + + // Update nTime every few seconds + UpdateTime(*pblock, pindexPrev); + nBlockTime = ByteReverse(pblock->nTime); + if (TestNet()) + { + // Changing pblock->nTime can change work required on testnet: + nBlockBits = ByteReverse(pblock->nBits); + hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + } + } + } } + catch (boost::thread_interrupted) + { + printf("BitcoinMiner terminated\n"); + throw; + } +} + +void GenerateBitcoins(bool fGenerate, CWallet* pwallet) +{ + static boost::thread_group* minerThreads = NULL; + + int nThreads = GetArg("-genproclimit", -1); + if (nThreads < 0) { + if (Params().NetworkID() == CChainParams::REGTEST) + nThreads = 1; + else + nThreads = boost::thread::hardware_concurrency(); + } + + if (minerThreads != NULL) + { + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; + } + + if (nThreads == 0 || !fGenerate) + return; + + minerThreads = new boost::thread_group(); + for (int i = 0; i < nThreads; i++) + minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); +} + + + diff --git a/src/miner.h b/src/miner.h new file mode 100644 index 0000000000..51d6a2e3ea --- /dev/null +++ b/src/miner.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_MINER_H +#define BITCOIN_MINER_H + +#include "core.h" +#include "wallet.h" + +/** Run the miner threads */ +void GenerateBitcoins(bool fGenerate, CWallet* pwallet); +/** Generate a new block, without valid proof-of-work */ +CBlockTemplate* CreateNewBlock(CReserveKey& reservekey); +/** Modify the extranonce in a block */ +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +/** Do mining precalculation */ +void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); +/** Check mined block */ +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); +/** Base sha256 mining transform */ +void SHA256Transform(void* pstate, void* pinput, const void* pinit); + +#endif // BITCOIN_MINER_H diff --git a/src/net.cpp b/src/net.cpp index bd9aa1f50f..4ee1895a80 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -129,7 +129,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer) bool RecvLine(SOCKET hSocket, string& strLine) { strLine = ""; - loop + while (true) { char c; int nBytes = recv(hSocket, &c, 1, 0); @@ -301,7 +301,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha { if (strLine.empty()) // HTTP response is separated from headers by blank line { - loop + while (true) { if (!RecvLine(hSocket, strLine)) { @@ -741,7 +741,7 @@ static list<CNode*> vNodesDisconnected; void ThreadSocketHandler() { unsigned int nPrevNodeCount = 0; - loop + while (true) { // // Disconnect nodes @@ -1105,7 +1105,7 @@ void ThreadMapPort() string strDesc = "Bitcoin " + FormatFullVersion(); try { - loop { + while (true) { #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, @@ -1268,7 +1268,7 @@ void ThreadOpenConnections() // Initiate network connections int64 nStart = GetTime(); - loop + while (true) { ProcessOneShot(); @@ -1309,7 +1309,7 @@ void ThreadOpenConnections() int64 nANow = GetAdjustedTime(); int nTries = 0; - loop + while (true) { // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections) CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index b0c45d6863..3b98334696 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -2,8 +2,6 @@ * W.J. van der Laan 2011-2012 */ -#include <QApplication> - #include "bitcoingui.h" #include "clientmodel.h" #include "walletmodel.h" @@ -17,6 +15,7 @@ #include "splashscreen.h" #include "intro.h" +#include <QApplication> #include <QMessageBox> #if QT_VERSION < 0x050000 #include <QTextCodec> diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index b502505f31..eeb6fe89bb 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -4,10 +4,11 @@ #include "bitcoinunits.h" #include "guiconstants.h" +#include <QApplication> #include <QHBoxLayout> #include <QKeyEvent> #include <QDoubleSpinBox> -#include <QApplication> + #include <qmath.h> // for qPow() BitcoinAmountField::BitcoinAmountField(QWidget *parent): diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 190da6caf8..8ec2f03fad 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -5,8 +5,6 @@ * The Bitcoin Developers 2011-2012 */ -#include <QApplication> - #include "bitcoingui.h" #include "transactiontablemodel.h" @@ -30,6 +28,7 @@ #include "macdockiconhandler.h" #endif +#include <QApplication> #include <QMenuBar> #include <QMenu> #include <QIcon> @@ -49,8 +48,6 @@ #endif #include <QMimeData> #include <QStyle> -#include <QSettings> -#include <QDesktopWidget> #include <QListWidget> #include <iostream> @@ -68,7 +65,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : rpcConsole(0), prevBlocks(0) { - restoreWindowGeometry(); + GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); #ifndef Q_OS_MAC if (!fIsTestnet) @@ -166,7 +163,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : BitcoinGUI::~BitcoinGUI() { - saveWindowGeometry(); + GUIUtil::saveWindowGeometry("nWindow", this); if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); #ifdef Q_OS_MAC @@ -425,28 +422,6 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) } #endif -void BitcoinGUI::saveWindowGeometry() -{ - QSettings settings; - settings.setValue("nWindowPos", pos()); - settings.setValue("nWindowSize", size()); -} - -void BitcoinGUI::restoreWindowGeometry() -{ - QSettings settings; - QPoint pos = settings.value("nWindowPos").toPoint(); - QSize size = settings.value("nWindowSize", QSize(850, 550)).toSize(); - if (!pos.x() && !pos.y()) - { - QRect screen = QApplication::desktop()->screenGeometry(); - pos.setX((screen.width()-size.width())/2); - pos.setY((screen.height()-size.height())/2); - } - resize(size); - move(pos); -} - void BitcoinGUI::optionsClicked() { if(!clientModel || !clientModel->getOptionsModel()) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 685ce8b430..6b9161539c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -122,10 +122,6 @@ private: void createTrayIcon(bool fIsTestnet); /** Create system tray menu (or setup the dock menu) */ void createTrayIconMenu(); - /** Save window size and position */ - void saveWindowGeometry(); - /** Restore window size and position */ - void restoreWindowGeometry(); public slots: /** Set number of connections shown in the UI */ diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 3d1e91efdc..32131bc39d 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,5 +1,3 @@ -#include <QApplication> - #include "guiutil.h" #include "bitcoinaddressvalidator.h" @@ -9,6 +7,7 @@ #include "util.h" #include "init.h" +#include <QApplication> #include <QDateTime> #include <QDoubleValidator> #include <QFont> @@ -24,6 +23,8 @@ #include <QFileDialog> #include <QDesktopServices> #include <QThread> +#include <QSettings> +#include <QDesktopWidget> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -487,6 +488,29 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; } #endif +void saveWindowGeometry(const QString& strSetting, QWidget *parent) +{ + QSettings settings; + settings.setValue(strSetting + "Pos", parent->pos()); + settings.setValue(strSetting + "Size", parent->size()); +} + +void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent) +{ + QSettings settings; + QPoint pos = settings.value(strSetting + "Pos").toPoint(); + QSize size = settings.value(strSetting + "Size", defaultSize).toSize(); + + if (!pos.x() && !pos.y()) { + QRect screen = QApplication::desktop()->screenGeometry(); + pos.setX((screen.width() - size.width()) / 2); + pos.setY((screen.height() - size.height()) / 2); + } + + parent->resize(size); + parent->move(pos); +} + HelpMessageBox::HelpMessageBox(QWidget *parent) : QMessageBox(parent) { diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index e2c7d18aa2..ca3e7fe91d 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -96,6 +96,11 @@ namespace GUIUtil bool GetStartOnSystemStartup(); bool SetStartOnSystemStartup(bool fAutoStart); + /** Save window size and position */ + void saveWindowGeometry(const QString& strSetting, QWidget *parent); + /** Restore window size and position */ + void restoreWindowGeometry(const QString& strSetting, const QSize &defaultSizeIn, QWidget *parent); + /** Help message for Bitcoin-Qt, shown with --help. */ class HelpMessageBox : public QMessageBox { diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 51f3c812e4..99db141c94 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -25,6 +25,7 @@ static const uint64 BLOCK_CHAIN_SIZE = 10LL * GB_BYTES; class FreespaceChecker : public QObject { Q_OBJECT + public: FreespaceChecker(Intro *intro); @@ -61,9 +62,16 @@ void FreespaceChecker::check() /* Find first parent that exists, so that fs::space does not fail */ fs::path parentDir = dataDir; + fs::path parentDirOld = fs::path(); while(parentDir.has_parent_path() && !fs::exists(parentDir)) { parentDir = parentDir.parent_path(); + + /* Check if we make any progress, break if not to prevent an infinite loop here */ + if (parentDirOld == parentDir) + break; + + parentDirOld = parentDir; } try { @@ -72,9 +80,9 @@ void FreespaceChecker::check() { if(fs::is_directory(dataDir)) { - QString separator = QDir::toNativeSeparators("/"); + QString separator = "<code>" + QDir::toNativeSeparators("/") + tr("name") + "</code>"; replyStatus = ST_OK; - replyMessage = tr("Directory already exists. Add <code>%1name</code> if you intend to create a new directory here.").arg(separator); + replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator); } else { replyStatus = ST_ERROR; replyMessage = tr("Path already exists, and is not a directory."); @@ -201,7 +209,7 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable } else { ui->freeSpace->setStyleSheet(""); } - ui->freeSpace->setText(freeString+"."); + ui->freeSpace->setText(freeString + "."); } /* Don't allow confirm in ERROR state */ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR); diff --git a/src/qt/intro.h b/src/qt/intro.h index b246c65a82..788799b7b0 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -37,6 +37,7 @@ public: * Determine default data directory for operating system. */ static QString getDefaultDataDirectory(); + signals: void requestCheck(); void stopThread(); diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 7628b39bd3..61af88d056 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.0" language="en"> -<defaultcodec>UTF-8</defaultcodec> <context> <name>AboutDialog</name> <message> @@ -689,7 +688,7 @@ Address: %4 <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+109"/> + <location filename="../bitcoin.cpp" line="+111"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</translation> </message> @@ -771,15 +770,38 @@ Address: %4 </message> </context> <context> + <name>FreespaceChecker</name> + <message> + <location filename="../intro.cpp" line="+60"/> + <source>A new data directory will be created.</source> + <translation>A new data directory will be created.</translation> + </message> + <message> + <location line="+17"/> + <source>Directory already exists. Add <code>%1name</code> if you intend to create a new directory here.</source> + <translation>Directory already exists. Add <code>%1name</code> if you intend to create a new directory here.</translation> + </message> + <message> + <location line="+3"/> + <source>Path already exists, and is not a directory.</source> + <translation>Path already exists, and is not a directory.</translation> + </message> + <message> + <location line="+7"/> + <source>Cannot create data directory here.</source> + <translation>Cannot create data directory here.</translation> + </message> +</context> +<context> <name>GUIUtil::HelpMessageBox</name> <message> <location filename="../guiutil.cpp" line="+493"/> - <location line="+12"/> + <location line="+13"/> <source>Bitcoin-Qt</source> <translation>Bitcoin-Qt</translation> </message> <message> - <location line="-12"/> + <location line="-13"/> <source>version</source> <translation>version</translation> </message> @@ -813,6 +835,59 @@ Address: %4 <source>Show splash screen on startup (default: 1)</source> <translation>Show splash screen on startup (default: 1)</translation> </message> + <message> + <location line="+1"/> + <source>Choose data directory on startup (default: 0)</source> + <translation>Choose data directory on startup (default: 0)</translation> + </message> +</context> +<context> + <name>Intro</name> + <message> + <location filename="../forms/intro.ui" line="+14"/> + <source>Welcome</source> + <translation>Welcome</translation> + </message> + <message> + <location line="+9"/> + <source>Welcome to Bitcoin-Qt.</source> + <translation>Welcome to Bitcoin-Qt.</translation> + </message> + <message> + <location line="+26"/> + <source>As this is the first time the program is launched, you can choose where Bitcoin-Qt will store its data.</source> + <translation>As this is the first time the program is launched, you can choose where Bitcoin-Qt will store its data.</translation> + </message> + <message> + <location line="+10"/> + <source>Bitcoin-Qt will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source> + <translation>Bitcoin-Qt will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</translation> + </message> + <message> + <location line="+10"/> + <source>Use the default data directory</source> + <translation>Use the default data directory</translation> + </message> + <message> + <location line="+7"/> + <source>Use a custom data directory:</source> + <translation>Use a custom data directory:</translation> + </message> + <message> + <location filename="../intro.cpp" line="+100"/> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <location line="+9"/> + <source>GB of free space available</source> + <translation>GB of free space available</translation> + </message> + <message> + <location line="+3"/> + <source>(of %1GB needed)</source> + <translation>(of %1GB needed)</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -1103,6 +1178,25 @@ Address: %4 </message> </context> <context> + <name>QObject</name> + <message> + <location filename="../bitcoin.cpp" line="+92"/> + <location filename="../intro.cpp" line="-32"/> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <location line="+1"/> + <source>Error: Specified data directory "%1" does not exist.</source> + <translation>Error: Specified data directory "%1" does not exist.</translation> + </message> + <message> + <location filename="../intro.cpp" line="+1"/> + <source>Error: Specified data directory "%1" can not be created.</source> + <translation>Error: Specified data directory "%1" can not be created.</translation> + </message> +</context> +<context> <name>QRCodeDialog</name> <message> <location filename="../forms/qrcodedialog.ui" line="+14"/> diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 7cfaef6079..903c54b39d 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,9 +1,9 @@ #include "notificator.h" +#include <QApplication> #include <QMetaType> #include <QVariant> #include <QIcon> -#include <QApplication> #include <QStyle> #include <QByteArray> #include <QSystemTrayIcon> diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 6b1b4e3d8e..7ebe5b4755 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -89,7 +89,7 @@ bool OptionsModel::Upgrade() settings.setValue("bImportFinished", true); // Move settings from old wallet.dat (if any): - CWalletDB walletdb("wallet.dat"); + CWalletDB walletdb(strWalletFile); QList<QString> intOptions; intOptions << "nDisplayUnit" << "nTransactionFee"; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 0b0bce55bb..0d31f24a13 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -2,14 +2,13 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <QApplication> - #include "paymentserver.h" #include "guiconstants.h" #include "ui_interface.h" #include "util.h" +#include <QApplication> #include <QByteArray> #include <QDataStream> #include <QDebug> diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ef72b17201..8953c36579 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -187,6 +187,7 @@ RPCConsole::RPCConsole(QWidget *parent) : historyPtr(0) { ui->setupUi(this); + GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); #ifndef Q_OS_MAC ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export")); @@ -209,6 +210,7 @@ RPCConsole::RPCConsole(QWidget *parent) : RPCConsole::~RPCConsole() { + GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); emit stopExecutor(); delete ui; } diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index e400278123..22cf04486b 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -2,9 +2,8 @@ #include "clientversion.h" #include "util.h" -#include <QPainter> -#undef loop /* ugh, remove this when the #define loop is gone from util.h */ #include <QApplication> +#include <QPainter> SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) : QSplashScreen(pixmap, f) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index a70c0958df..25111d3787 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -6,6 +6,7 @@ #include "chainparams.h" #include "db.h" #include "init.h" +#include "miner.h" #include "bitcoinrpc.h" using namespace json_spirit; diff --git a/src/script.cpp b/src/script.cpp index 14fe80e207..5699fbfb6a 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1163,7 +1163,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); - loop + while (true) { if (pc1 == script1.end() && pc2 == script2.end()) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index af284653dd..bd1d998c4f 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -4,6 +4,7 @@ #include "main.h" #include "uint256.h" #include "util.h" +#include "miner.h" #include "wallet.h" extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); diff --git a/src/util.cpp b/src/util.cpp index bfb6d75838..049e55b7d6 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -311,7 +311,7 @@ string vstrprintf(const char *format, va_list ap) char* p = buffer; int limit = sizeof(buffer); int ret; - loop + while (true) { va_list arg_ptr; va_copy(arg_ptr, ap); @@ -371,7 +371,7 @@ void ParseString(const string& str, char c, vector<string>& v) return; string::size_type i1 = 0; string::size_type i2; - loop + while (true) { i2 = str.find(c, i1); if (i2 == str.npos) @@ -487,7 +487,7 @@ vector<unsigned char> ParseHex(const char* psz) { // convert hex dump to vector vector<unsigned char> vch; - loop + while (true) { while (isspace(*psz)) psz++; @@ -941,7 +941,7 @@ string DecodeBase32(const string& str) bool WildcardMatch(const char* psz, const char* mask) { - loop + while (true) { switch (*mask) { @@ -1118,6 +1118,7 @@ boost::filesystem::path GetPidFile() return pathPidFile; } +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { FILE* file = fopen(path.string().c_str(), "w"); @@ -1127,6 +1128,7 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid) fclose(file); } } +#endif bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) { diff --git a/src/util.h b/src/util.h index bee2749c16..9aea564406 100644 --- a/src/util.h +++ b/src/util.h @@ -35,7 +35,6 @@ typedef unsigned long long uint64; static const int64 COIN = 100000000; static const int64 CENT = 1000000; -#define loop for (;;) #define BEGIN(a) ((char*)&(a)) #define END(a) ((char*)&((&(a))[1])) #define UBEGIN(a) ((unsigned char*)&(a)) @@ -208,7 +207,9 @@ boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); boost::filesystem::path GetPidFile(); +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid); +#endif void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); diff --git a/src/wallet.cpp b/src/wallet.cpp index 488787f967..88b07c9d76 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -892,19 +892,17 @@ void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away // that these are our transactions. - static int64 nNextTime; - if (GetTime() < nNextTime) + if (GetTime() < nNextResend) return; - bool fFirst = (nNextTime == 0); - nNextTime = GetTime() + GetRand(30 * 60); + bool fFirst = (nNextResend == 0); + nNextResend = GetTime() + GetRand(30 * 60); if (fFirst) return; // Only do it if there's been a new block since last time - static int64 nLastTime; - if (nTimeBestReceived < nLastTime) + if (nTimeBestReceived < nLastResend) return; - nLastTime = GetTime(); + nLastResend = GetTime(); // Rebroadcast any of our txes that aren't in a block yet printf("ResendWalletTransactions()\n"); @@ -1196,7 +1194,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, LOCK2(cs_main, cs_wallet); { nFeeRet = nTransactionFee; - loop + while (true) { wtxNew.vin.clear(); wtxNew.vout.clear(); diff --git a/src/wallet.h b/src/wallet.h index 36b3608fb0..3474045e32 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -80,6 +80,9 @@ private: // the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded int nWalletMaxVersion; + int64 nNextResend; + int64 nLastResend; + public: mutable CCriticalSection cs_wallet; @@ -101,6 +104,8 @@ public: nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; nOrderPosNext = 0; + nNextResend = 0; + nLastResend = 0; } CWallet(std::string strWalletFileIn) { @@ -111,6 +116,8 @@ public: nMasterKeyMaxID = 0; pwalletdbEncryption = NULL; nOrderPosNext = 0; + nNextResend = 0; + nLastResend = 0; } std::map<uint256, CWalletTx> mapWallet; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 7aad779767..014d8cbe29 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -73,7 +73,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin if (!pcursor) throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); unsigned int fFlags = DB_SET_RANGE; - loop + while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); @@ -437,7 +437,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) return DB_CORRUPT; } - loop + while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); |