<commit_before>#include "queue thread safe.hpp"
#include "gtest/gtest.h"
#include <thread>
#include <algorithm>
#include "aux_tests.hpp"

TEST(Push,HandleBasicOperation){
	std::threadsafe::queue<int> queue;

	int out;
	for (int i = 1;i <= 10;i++){
			queue.push(i);

			queue.wait_back(out);
			EXPECT_EQ(i,out);

			queue.wait_top(out);
			EXPECT_EQ(out,1);
			EXPECT_EQ(i,queue.size());
	}

	for (int i = 1;i <= 10;i++){
			queue.wait_pop(out);
			EXPECT_EQ(i,out);
			EXPECT_EQ(10-i,queue.size());
	}
}

TEST(Push,ThreadSafety){
	std::threadsafe::queue<int> queue;
	testPushThreadSafety(queue);
}

TEST(Push,UpperBound){
	std::threadsafe::queue<int> queue;
	testPushUpperBound(queue);
}

TEST(Try_pop,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	int out;
	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(10-i+1,queue.size());
		ASSERT_EQ(true,queue.try_pop(out));
		ASSERT_EQ(i,out);
	}
	ASSERT_EQ(0,queue.size());
	ASSERT_EQ(false,queue.try_pop(out));
}

TEST(Try_pop,ThreadSafety){
	std::threadsafe::queue<int> queue;
	testPopThreadSafety(queue);
}

TEST(Wait_pop,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	int out;
	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(10-i+1,queue.size());
		queue.wait_pop(out);
		ASSERT_EQ(i,out);
	}
	ASSERT_EQ(0,queue.size());
}

TEST(Wait_pop,Timer){
	std::threadsafe::queue<int> queue;
	testTimerPop(queue);
}

TEST(Try_top,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	int out;
	ASSERT_EQ(false,queue.try_top(out));
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(true,queue.try_top(out));
		ASSERT_EQ(10,queue.size());
		ASSERT_EQ(1,out);
	}
}

TEST(Try_top,ThreadSafety){
	std::threadsafe::queue<int> queue;
	constexpr int NUM_PRODUCERS = 1;
	constexpr int NUM_CONSUMERS = 1;
	constexpr int ITERATIONS = 10;

	auto producer = [&](int id,int it){
				queue.push(it);
			};

	int n = 0;
	auto consumer = [&](int id,int it){
				int out;

				while (!queue.try_top(out) && out < ITERATIONS){
					ASSERT_EQ(out,n);
					n++;
				}
			};

	launchThreads(producer,consumer,NUM_PRODUCERS,NUM_CONSUMERS,ITERATIONS);

}

TEST(Wait_top,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	int out;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	for (int i = 10;i >= 1;i--){
		queue.wait_top(out);
		ASSERT_EQ(10,queue.size());
		ASSERT_EQ(1,out);
	}

}

TEST(Wait_top,Timer){
	std::threadsafe::queue<int> queue;

	std::thread producer([&]{
		queue.push(1);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		queue.push(2);
		std::this_thread::sleep_for(std::chrono::milliseconds(50));
		queue.push(3);
	});

	std::thread consumer([&]{
		int output;

		try {
			queue.wait_top(output,std::chrono::milliseconds(5));
			ASSERT_EQ(1,output);
			queue.wait_pop(output);

			queue.wait_top(output,std::chrono::milliseconds(15));
			ASSERT_EQ(2,output);
			queue.wait_pop(output);
		} catch(std::threadsafe::Time_Expired e){
			FAIL() << " exception Time_Expired throwed";
		}

		try {
			queue.wait_top(output,std::chrono::milliseconds(1));
			FAIL() << " exception didn't throw!";
		} catch(std::threadsafe::Time_Expired e){
		}
	});

	producer.join();
	consumer.join();
}

TEST(EMPTY,HanbleBasicOperation){
	std::threadsafe::queue<int> queue;
	ASSERT_TRUE(queue.empty());
	queue.push(1);
	ASSERT_FALSE(queue.empty());
}
<commit_msg>Added test wait_back timer at queue<commit_after>#include "queue thread safe.hpp"
#include "gtest/gtest.h"
#include <thread>
#include <algorithm>
#include "aux_tests.hpp"

TEST(Push,HandleBasicOperation){
	std::threadsafe::queue<int> queue;

	int out;
	for (int i = 1;i <= 10;i++){
			queue.push(i);

			queue.wait_back(out);
			EXPECT_EQ(i,out);

			queue.wait_top(out);
			EXPECT_EQ(out,1);
			EXPECT_EQ(i,queue.size());
	}

	for (int i = 1;i <= 10;i++){
			queue.wait_pop(out);
			EXPECT_EQ(i,out);
			EXPECT_EQ(10-i,queue.size());
	}
}

TEST(Push,ThreadSafety){
	std::threadsafe::queue<int> queue;
	testPushThreadSafety(queue);
}

TEST(Push,UpperBound){
	std::threadsafe::queue<int> queue;
	testPushUpperBound(queue);
}

TEST(Try_pop,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	int out;
	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(10-i+1,queue.size());
		ASSERT_EQ(true,queue.try_pop(out));
		ASSERT_EQ(i,out);
	}
	ASSERT_EQ(0,queue.size());
	ASSERT_EQ(false,queue.try_pop(out));
}

TEST(Try_pop,ThreadSafety){
	std::threadsafe::queue<int> queue;
	testPopThreadSafety(queue);
}

TEST(Wait_pop,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	int out;
	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(10-i+1,queue.size());
		queue.wait_pop(out);
		ASSERT_EQ(i,out);
	}
	ASSERT_EQ(0,queue.size());
}

TEST(Wait_pop,Timer){
	std::threadsafe::queue<int> queue;
	testTimerPop(queue);
}

TEST(Try_top,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	int out;
	ASSERT_EQ(false,queue.try_top(out));
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	for (int i = 1;i <= 10;i++){
		ASSERT_EQ(true,queue.try_top(out));
		ASSERT_EQ(10,queue.size());
		ASSERT_EQ(1,out);
	}
}

TEST(Try_top,ThreadSafety){
	std::threadsafe::queue<int> queue;
	constexpr int NUM_PRODUCERS = 1;
	constexpr int NUM_CONSUMERS = 1;
	constexpr int ITERATIONS = 10;

	auto producer = [&](int id,int it){
				queue.push(it);
			};

	int n = 0;
	auto consumer = [&](int id,int it){
				int out;

				while (!queue.try_top(out) && out < ITERATIONS){
					ASSERT_EQ(out,n);
					n++;
				}
			};

	launchThreads(producer,consumer,NUM_PRODUCERS,NUM_CONSUMERS,ITERATIONS);

}

TEST(Wait_top,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	int out;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	for (int i = 10;i >= 1;i--){
		queue.wait_top(out);
		ASSERT_EQ(10,queue.size());
		ASSERT_EQ(1,out);
	}

}

TEST(Wait_top,Timer){
	std::threadsafe::queue<int> queue;

	std::thread producer([&]{
		queue.push(1);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		queue.push(2);
		std::this_thread::sleep_for(std::chrono::milliseconds(50));
		queue.push(3);
	});

	std::thread consumer([&]{
		int output;

		try {
			queue.wait_top(output,std::chrono::milliseconds(5));
			ASSERT_EQ(1,output);
			queue.wait_pop(output);

			queue.wait_top(output,std::chrono::milliseconds(15));
			ASSERT_EQ(2,output);
			queue.wait_pop(output);
		} catch(std::threadsafe::Time_Expired e){
			FAIL() << " exception Time_Expired throwed";
		}

		try {
			queue.wait_top(output,std::chrono::milliseconds(1));
			FAIL() << " exception didn't throw!";
		} catch(std::threadsafe::Time_Expired e){
		}
	});

	producer.join();
	consumer.join();
}

TEST(Wait_back,HandleBasicOperation){
	std::threadsafe::queue<int> queue;
	int out;
	for (int i = 1;i <= 10;i++){
		queue.push(i);
	}

	for (int i = 10;i >= 1;i--){
		queue.wait_back(out);
		ASSERT_EQ(10,queue.size());
		ASSERT_EQ(10,out);
	}

}

TEST(Wait_back,Timer){
	std::threadsafe::queue<int> queue;

	std::thread producer([&]{
		queue.push(1);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		queue.push(2);
		std::this_thread::sleep_for(std::chrono::milliseconds(50));
		queue.push(3);
	});

	std::thread consumer([&]{
		int output;

		try {
			queue.wait_back(output,std::chrono::milliseconds(5));
			ASSERT_EQ(1,output);
			queue.wait_pop(output);

			queue.wait_back(output,std::chrono::milliseconds(15));
			ASSERT_EQ(2,output);
			queue.wait_pop(output);
		} catch(std::threadsafe::Time_Expired e){
			FAIL() << " exception Time_Expired throwed";
		}

		try {
			queue.wait_back(output,std::chrono::milliseconds(1));
			FAIL() << " exception didn't throw!";
		} catch(std::threadsafe::Time_Expired e){
		}
	});

	producer.join();
	consumer.join();
}
TEST(EMPTY,HanbleBasicOperation){
	std::threadsafe::queue<int> queue;
	ASSERT_TRUE(queue.empty());
	queue.push(1);
	ASSERT_FALSE(queue.empty());
}
<|endoftext|>


<commit_before>#include "timeout.h"

#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>

#include <atomic>
#include <cerrno>
#include <chrono>
#include <csignal>
#include <iostream>
#include <stdexcept>
#include <string>

#include "macros.h"
#include "pybind11/pybind11.h"
#include "util.h"

namespace atheris {

namespace py = pybind11;

int64_t timeout_secs = 300;
std::atomic<int64_t> unit_start_time(
    std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now().time_since_epoch())
        .count());

sighandler_t libfuzzer_alarm_signal = SIG_DFL;
sighandler_t python_alarm_signal = nullptr;

NO_SANITIZE
void SetTimeout(int timeout_secs) { ::atheris::timeout_secs = timeout_secs; }

// A back SIGALRM signal handler, registered inside of HandleAlarm, to call
// libFuzzer's handler if the Python handler never gets called.
NO_SANITIZE
void LibfuzzerAlarmSignalCallback(int signum) {
  std::cout << "ALARM: Did not return to Python execution within 1 second "
               "after timeout. This likely means your fuzzer timed out in "
               "native code. "
               "Falling back to native timeout handling."
            << std::endl;

  if (libfuzzer_alarm_signal == nullptr || libfuzzer_alarm_signal == SIG_DFL ||
      libfuzzer_alarm_signal == SIG_IGN) {
    _exit(1);
  }
  libfuzzer_alarm_signal(signum);
}

// Our SIGALRM signal handler.
NO_SANITIZE
void HandleAlarm(int signum) {
  int64_t current_time =
      std::chrono::duration_cast<std::chrono::seconds>(
          std::chrono::system_clock::now().time_since_epoch())
          .count();
  int64_t duration = current_time - unit_start_time;

  if (duration > timeout_secs) {
    std::cout << Colorize(STDOUT_FILENO,
                          "\n === Timeout: " + std::to_string(duration) +
                              "s elapsed, timeout=" +
                              std::to_string(timeout_secs) + "s ===")
              << std::endl;

    // Queue the python backtrace-printing handler.
    python_alarm_signal(signum);

    // If the handler doesn't get called in 1 second, fall back to the libFuzzer
    // handler.
    struct sigaction action;
    checked_sigaction(SIGALRM, nullptr, &action);

    action.sa_handler = LibfuzzerAlarmSignalCallback;
    checked_sigaction(SIGALRM, &action, nullptr);

    alarm(1);  // Set 1 second until alarm.
  }
}

NO_SANITIZE
void SetupTimeoutAlarm() {
  // If python_alarm_signal isn't set, either SetupPythonSigaction wasn't called
  // or it returned false. Timeouts are unsupported.
  if (!python_alarm_signal) return;

  unit_start_time = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count();

  // set up our timer. The `timeout_secs / 2 + 1` comes from libFuzzer. The
  // signal handler will check that the timeout has actually been exceeded
  // before exiting. This means that a test case will be guaranteed to timeout
  // after exceeding the timeout by 50%, not 100%.
  struct itimerval tim {
    {timeout_secs / 2 + 1, 0}, { timeout_secs / 2 + 1, 0 }
  };
  if (setitimer(ITIMER_REAL, &tim, nullptr)) {
    std::cerr << Colorize(STDERR_FILENO,
                          "Failed to set timer - will not detect timeouts.")
              << std::endl;
  }

  struct sigaction action;
  checked_sigaction(SIGALRM, nullptr, &action);

  libfuzzer_alarm_signal = action.sa_handler;

  action.sa_handler = HandleAlarm;
  checked_sigaction(SIGALRM, &action, nullptr);
}

void PrintPythonCallbacks(int signum, py::object frame) {
  // Cancel any further queued alarm.
  alarm(0);

  // Print the Python trace.
  auto faulthandler = py::module::import("faulthandler");
  faulthandler.attr("dump_traceback")();
  if (libfuzzer_alarm_signal == nullptr || libfuzzer_alarm_signal == SIG_DFL ||
      libfuzzer_alarm_signal == SIG_IGN) {
    exit(1);
  }

  // exit.
  libfuzzer_alarm_signal(signum);
}

bool SetupPythonSigaction() {
  // So, we want to print the Python stack on a timeout event. However, this is
  // not safe during a native signal handler. Instead, we register a Python
  // signal handler, and then invoke that from within our native signal handler.
  // The registered Python handler doesn't actually trigger until execution
  // returns to the Python interpreter (the real handler just sets a flag),
  // which is why this is safe. However, if code execution fails to return to
  // the Python interpreter (such as an infinite loop in native code), it will
  // never run. We then have a choice: eiher we try printing the Python trace
  // from within the handler anyway, which is technically unsafe; or we just
  // print the native trace. We print the native trace for now, but this might
  // change in the future.

  struct sigaction orig_action;
  checked_sigaction(SIGALRM, nullptr, &orig_action);

  // If someone has provided a SIGALRM handler, we shouldn't override that -
  // print a warning and break.
  if (orig_action.sa_handler != nullptr && orig_action.sa_handler != SIG_DFL &&
      orig_action.sa_handler != SIG_IGN) {
    std::cerr << "WARNING: SIGALRM handler already defined at address "
              << reinterpret_cast<void*>(orig_action.sa_handler)
              << ". Fuzzer timeout will not work." << std::endl;
    return false;
  }

  auto signal_module = py::module::import("signal");
  signal_module.attr("signal")(SIGALRM, py::cpp_function(PrintPythonCallbacks));

  struct sigaction action;
  checked_sigaction(SIGALRM, nullptr, &action);

  python_alarm_signal = action.sa_handler;

  // Clear the handler that was just registered. This ensures libFuzzer will
  // register its own signal handler. (It has the same behavior as here, where
  // it won't register a handler if one is already registered.)
  if (sigaction(SIGALRM, &orig_action, nullptr)) {
    std::cerr << "sigaction (get): " << strerror(errno) << std::endl;
    exit(1);
  }

  checked_sigaction(SIGALRM, nullptr, &action);

  return true;
}

NO_SANITIZE
void RefreshTimeout() {
  unit_start_time = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count();
}

}  // namespace atheris
<commit_msg>Refactor in some helper functions to timeout.cc.<commit_after>#include "timeout.h"

#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>

#include <atomic>
#include <cerrno>
#include <chrono>
#include <csignal>
#include <iostream>
#include <stdexcept>
#include <string>

#include "macros.h"
#include "pybind11/pybind11.h"
#include "util.h"

namespace atheris {

namespace py = pybind11;

int64_t timeout_secs = 300;
std::atomic<int64_t> unit_start_time(
    std::chrono::duration_cast<std::chrono::seconds>(
        std::chrono::system_clock::now().time_since_epoch())
        .count());

sighandler_t libfuzzer_alarm_signal = SIG_DFL;
sighandler_t python_alarm_signal = nullptr;

NO_SANITIZE
void SetTimeout(int timeout_secs) { ::atheris::timeout_secs = timeout_secs; }

NO_SANITIZE
bool is_null_or_default(sighandler_t h) {
  return h == nullptr || h == SIG_DFL || h == SIG_IGN;
}

// A back SIGALRM signal handler, registered inside of HandleAlarm, to call
// libFuzzer's handler if the Python handler never gets called.
NO_SANITIZE
void LibfuzzerAlarmSignalCallback(int signum) {
  std::cout << "ALARM: Did not return to Python execution within 1 second "
               "after timeout. This likely means your fuzzer timed out in "
               "native code. "
               "Falling back to native timeout handling."
            << std::endl;

  if (is_null_or_default(libfuzzer_alarm_signal)) {
    _exit(1);
  }
  libfuzzer_alarm_signal(signum);
}

// Our SIGALRM signal handler.
NO_SANITIZE
void HandleAlarm(int signum) {
  int64_t current_time =
      std::chrono::duration_cast<std::chrono::seconds>(
          std::chrono::system_clock::now().time_since_epoch())
          .count();
  int64_t duration = current_time - unit_start_time;

  if (duration > timeout_secs) {
    std::cout << Colorize(STDOUT_FILENO,
                          "\n === Timeout: " + std::to_string(duration) +
                              "s elapsed, timeout=" +
                              std::to_string(timeout_secs) + "s ===")
              << std::endl;

    // Queue the python backtrace-printing handler.
    python_alarm_signal(signum);

    // If the handler doesn't get called in 1 second, fall back to the libFuzzer
    // handler.
    struct sigaction action;
    checked_sigaction(SIGALRM, nullptr, &action);

    action.sa_handler = LibfuzzerAlarmSignalCallback;
    checked_sigaction(SIGALRM, &action, nullptr);

    alarm(1);  // Set 1 second until alarm.
  }
}

NO_SANITIZE
void signal_or_exit(sighandler_t handler, int signum) {
  if (is_null_or_default(handler)) {
    exit(1);
  }
  handler(signum);
}

// Returns the old handle in the `signum` signal replacing it with `new_handle`.
NO_SANITIZE
sighandler_t replace_handle(int signum, sighandler_t new_handle) {
  struct sigaction action;
  checked_sigaction(signum, nullptr, &action);
  auto old_handle = action.sa_handler;
  action.sa_handler = new_handle;
  checked_sigaction(signum, &action, nullptr);
  return old_handle;
}

NO_SANITIZE
void SetupTimeoutAlarm() {
  // If python_alarm_signal isn't set, either SetupPythonSigaction wasn't called
  // or it returned false. Timeouts are unsupported.
  if (!python_alarm_signal) return;

  unit_start_time = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count();

  // set up our timer. The `timeout_secs / 2 + 1` comes from libFuzzer. The
  // signal handler will check that the timeout has actually been exceeded
  // before exiting. This means that a test case will be guaranteed to timeout
  // after exceeding the timeout by 50%, not 100%.
  struct itimerval tim {
    {timeout_secs / 2 + 1, 0}, { timeout_secs / 2 + 1, 0 }
  };
  if (setitimer(ITIMER_REAL, &tim, nullptr)) {
    std::cerr << Colorize(STDERR_FILENO,
                          "Failed to set timer - will not detect timeouts.")
              << std::endl;
  }

  libfuzzer_alarm_signal = replace_handle(SIGALRM, HandleAlarm);
}

void PrintPythonCallbacks(int signum, py::object frame) {
  // Cancel any further queued alarm.
  alarm(0);

  // Print the Python trace.
  auto faulthandler = py::module::import("faulthandler");
  faulthandler.attr("dump_traceback")();
  signal_or_exit(libfuzzer_alarm_signal, signum);
}

bool SetupPythonSigaction() {
  // So, we want to print the Python stack on a timeout event. However, this is
  // not safe during a native signal handler. Instead, we register a Python
  // signal handler, and then invoke that from within our native signal handler.
  // The registered Python handler doesn't actually trigger until execution
  // returns to the Python interpreter (the real handler just sets a flag),
  // which is why this is safe. However, if code execution fails to return to
  // the Python interpreter (such as an infinite loop in native code), it will
  // never run. We then have a choice: eiher we try printing the Python trace
  // from within the handler anyway, which is technically unsafe; or we just
  // print the native trace. We print the native trace for now, but this might
  // change in the future.

  struct sigaction orig_action;
  checked_sigaction(SIGALRM, nullptr, &orig_action);

  // If someone has provided a SIGALRM handler, we shouldn't override that -
  // print a warning and break.
  if (!is_null_or_default(orig_action.sa_handler)) {
    std::cerr << "WARNING: SIGALRM handler already defined at address "
              << reinterpret_cast<void*>(orig_action.sa_handler)
              << ". Fuzzer timeout will not work." << std::endl;
    return false;
  }

  auto signal_module = py::module::import("signal");
  signal_module.attr("signal")(SIGALRM, py::cpp_function(PrintPythonCallbacks));

  struct sigaction action;
  checked_sigaction(SIGALRM, nullptr, &action);

  python_alarm_signal = action.sa_handler;

  // Clear the handler that was just registered. This ensures libFuzzer will
  // register its own signal handler. (It has the same behavior as here, where
  // it won't register a handler if one is already registered.)
  if (sigaction(SIGALRM, &orig_action, nullptr)) {
    std::cerr << "sigaction (get): " << strerror(errno) << std::endl;
    exit(1);
  }

  checked_sigaction(SIGALRM, nullptr, &action);

  return true;
}

NO_SANITIZE
void RefreshTimeout() {
  unit_start_time = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch())
                        .count();
}

}  // namespace atheris
<|endoftext|>


<commit_before>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © ") + tr("2009-%1 The Bitcoin developers").arg(COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<commit_msg>aboutdialog: use just "The Bitcoin developers" as tr()-string<commit_after>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers"));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<|endoftext|>


<commit_before>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

// Copyright year (2009-this)
// Todo: update this when changing our copyright comments in the source
const int ABOUTDIALOG_COPYRIGHT_YEAR = 2013;

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString("
") + tr("Copyright") + QString(" © ") + tr("2011-%1 The Gaelcoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<commit_msg>changes<commit_after>#include "aboutdialog.h"
#include "ui_aboutdialog.h"

#include "clientmodel.h"
#include "clientversion.h"

// Copyright year (2009-this)
// Todo: update this when changing our copyright comments in the source
const int ABOUTDIALOG_COPYRIGHT_YEAR = 2014;

AboutDialog::AboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AboutDialog)
{
    ui->setupUi(this);

    // Set current copyright year
    ui->copyrightLabel->setText(tr("Copyright") + QString(" © 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin developers") + QString("
") + tr("Copyright") + QString(" © ") + tr("2014 The Gaelcoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR));
}

void AboutDialog::setModel(ClientModel *model)
{
    if(model)
    {
        ui->versionLabel->setText(model->formatFullVersion());
    }
}

AboutDialog::~AboutDialog()
{
    delete ui;
}

void AboutDialog::on_buttonBox_accepted()
{
    close();
}
<|endoftext|>


<commit_before>#include "walletmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"

#include "ui_interface.h"
#include "wallet.h"
#include "walletdb.h" // for BackupWallet
#include "base58.h"

#include <QSet>
#include <QTimer>

WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
    QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
    transactionTableModel(0),
    cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
    cachedNumTransactions(0),
    cachedEncryptionStatus(Unencrypted),
    cachedNumBlocks(0)
{
    addressTableModel = new AddressTableModel(wallet, this);
    transactionTableModel = new TransactionTableModel(wallet, this);

    // This timer will be fired repeatedly to update the balance
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

WalletModel::~WalletModel()
{
    unsubscribeFromCoreSignals();
}

qint64 WalletModel::getBalance() const
{
    return wallet->GetBalance();
}

qint64 WalletModel::getUnconfirmedBalance() const
{
    return wallet->GetUnconfirmedBalance();
}

qint64 WalletModel::getStake() const
{
    return wallet->GetStake();
}

qint64 WalletModel::getImmatureBalance() const
{
    return wallet->GetImmatureBalance();
}

int WalletModel::getNumTransactions() const
{
    int numTransactions = 0;
    {
        LOCK(wallet->cs_wallet);
        numTransactions = wallet->mapWallet.size();
    }
    return numTransactions;
}

void WalletModel::updateStatus()
{
    EncryptionStatus newEncryptionStatus = getEncryptionStatus();

    if(cachedEncryptionStatus != newEncryptionStatus)
        emit encryptionStatusChanged(newEncryptionStatus);
}

void WalletModel::pollBalanceChanged()
{
    if(nBestHeight != cachedNumBlocks)
    {
        // Balance and number of transactions might have changed
        cachedNumBlocks = nBestHeight;
        checkBalanceChanged();
    }
}

void WalletModel::checkBalanceChanged()
{
    qint64 newBalance = getBalance();
    qint64 newStake = getStake();
    qint64 newUnconfirmedBalance = getUnconfirmedBalance();
    qint64 newImmatureBalance = getImmatureBalance();

    if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
    {
        cachedBalance = newBalance;
        cachedStake = newStake;
        cachedUnconfirmedBalance = newUnconfirmedBalance;
        cachedImmatureBalance = newImmatureBalance;
        emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
    }
}

void WalletModel::updateTransaction(const QString &hash, int status)
{
    if(transactionTableModel)
        transactionTableModel->updateTransaction(hash, status);

    // Balance and number of transactions might have changed
    checkBalanceChanged();

    int newNumTransactions = getNumTransactions();
    if(cachedNumTransactions != newNumTransactions)
    {
        cachedNumTransactions = newNumTransactions;
        emit numTransactionsChanged(newNumTransactions);
    }
}

void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
{
    if(addressTableModel)
        addressTableModel->updateEntry(address, label, isMine, status);
}

bool WalletModel::validateAddress(const QString &address)
{
    CBitcoinAddress addressParsed(address.toStdString());
    return addressParsed.IsValid();
}

WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, int nSplitBlock, const CCoinControl *coinControl)
{
    qint64 total = 0;
    QSet<QString> setAddress;
    QString hex;

    if(recipients.empty())
    {
        return OK;
    }

    // Pre-check input data for validity
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        if(!validateAddress(rcp.address))
        {
            return InvalidAddress;
        }
        setAddress.insert(rcp.address);

        if(rcp.amount <= 0)
        {
            return InvalidAmount;
        }
        total += rcp.amount;
    }

    if(recipients.size() > setAddress.size())
    {
        return DuplicateAddress;
    }

    int64_t nBalance = 0;
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins, true, coinControl);

    BOOST_FOREACH(const COutput& out, vCoins)
        nBalance += out.tx->vout[out.i].nValue;

    if(total > nBalance)
    {
        return AmountExceedsBalance;
    }

    if((total + nTransactionFee) > nBalance)
    {
        return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
    }

    {
        LOCK2(cs_main, wallet->cs_wallet);

        // Sendmany
        std::vector<std::pair<CScript, int64_t> > vecSend;
        foreach(const SendCoinsRecipient &rcp, recipients)
        {
            CScript scriptPubKey;
            scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
            vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
        }

        CWalletTx wtx;
        CReserveKey keyChange(wallet);
        int64_t nFeeRequired = 0;
        bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nSplitBlock, coinControl);

        if(!fCreated)
        {
            if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
            {
                return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
            }
            return TransactionCreationFailed;
        }
        if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
        {
            return Aborted;
        }
        if(!wallet->CommitTransaction(wtx, keyChange))
        {
            return TransactionCommitFailed;
        }
        hex = QString::fromStdString(wtx.GetHash().GetHex());
    }

    // Add addresses / update labels that we've sent to to the address book
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        std::string strAddress = rcp.address.toStdString();
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        std::string strLabel = rcp.label.toStdString();
        {
            LOCK(wallet->cs_wallet);

            std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest);

            // Check if we have a new address or an updated label
            if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
            {
                wallet->SetAddressBookName(dest, strLabel);
            }
        }
    }

    return SendCoinsReturn(OK, 0, hex);
}

OptionsModel *WalletModel::getOptionsModel()
{
    return optionsModel;
}

AddressTableModel *WalletModel::getAddressTableModel()
{
    return addressTableModel;
}

TransactionTableModel *WalletModel::getTransactionTableModel()
{
    return transactionTableModel;
}

WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
    if(!wallet->IsCrypted())
    {
        return Unencrypted;
    }
    else if(wallet->IsLocked())
    {
        return Locked;
    }
    else
    {
        return Unlocked;
    }
}

bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
    if(encrypted)
    {
        // Encrypt
        return wallet->EncryptWallet(passphrase);
    }
    else
    {
        // Decrypt -- TODO; not supported yet
        return false;
    }
}

bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
{
    if(locked)
    {
        // Lock
        return wallet->Lock();
    }
    else
    {
        // Unlock
        return wallet->Unlock(passPhrase);
    }
}

bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
    bool retval;
    {
        LOCK(wallet->cs_wallet);
        wallet->Lock(); // Make sure wallet is locked before attempting pass change
        retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
    }
    return retval;
}

bool WalletModel::backupWallet(const QString &filename)
{
    return BackupWallet(*wallet, filename.toLocal8Bit().data());
}

// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
    OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
    QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}

static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status)
{
    OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status);
    QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())),
                              Q_ARG(QString, QString::fromStdString(label)),
                              Q_ARG(bool, isMine),
                              Q_ARG(int, status));
}

static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
    OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
    QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(hash.GetHex())),
                              Q_ARG(int, status));
}

void WalletModel::subscribeToCoreSignals()
{
    // Connect signals to wallet
    wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

void WalletModel::unsubscribeFromCoreSignals()
{
    // Disconnect signals from wallet
    wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
    bool was_locked = getEncryptionStatus() == Locked;

    if ((!was_locked) && fWalletUnlockStakingOnly)
    {
       setWalletLocked(true);
       was_locked = getEncryptionStatus() == Locked;

    }
    if(was_locked)
    {
        // Request UI to unlock wallet
        emit requireUnlock();
    }
    // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
    bool valid = getEncryptionStatus() != Locked;

    return UnlockContext(this, valid, was_locked && !fWalletUnlockStakingOnly);
}

WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
        wallet(wallet),
        valid(valid),
        relock(relock)
{
}

WalletModel::UnlockContext::~UnlockContext()
{
    if(valid && relock)
    {
        wallet->setWalletLocked(true);
    }
}

void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
    // Transfer context; old object no longer relocks wallet
    *this = rhs;
    rhs.relock = false;
}

bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
    return wallet->GetPubKey(address, vchPubKeyOut);
}

// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
    BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vOutputs.push_back(out);
    }
}

// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins);
    std::vector<COutPoint> vLockedCoins;

    // add locked coins
    BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vCoins.push_back(out);
    }

    BOOST_FOREACH(const COutput& out, vCoins)
    {
        COutput cout = out;

        while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
        {
            if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
            cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
        }

        CTxDestination address;
        if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
        mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
    }
}

bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
{
	COutPoint outpoint(hash, n);
	return std::find(wallet->lockedcoins.vLockedCoins.begin(), wallet->lockedcoins.vLockedCoins.end(), outpoint) != wallet->lockedcoins.vLockedCoins.end();
}

void WalletModel::lockCoin(COutPoint& outpoint)
{
    wallet->lockedcoins.vLockedCoins.push_back(outpoint);
	CWalletDB walletdb(wallet->strWalletFile);

	return;
}

void WalletModel::unlockCoin(COutPoint& outpoint)
{
	for(std::vector<COutPoint>::iterator it = wallet->lockedcoins.vLockedCoins.begin(); it != wallet->lockedcoins.vLockedCoins.end(); it++)
	{
		if (*it == outpoint)
		{
			wallet->lockedcoins.vLockedCoins.erase(it);
			break;
		}
	}

	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::listLockedCoins(std::vector<COutPoint>& vLockedCoins)
{
	vLockedCoins = wallet->lockedcoins.vLockedCoins;
	return;
}

//Information for coin control
void WalletModel::getStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight)
{
	wallet->GetStakeWeightFromValue(nTime, nValue, nWeight);
}

void WalletModel::setSplitBlock(bool fSplitBlock)
{
	wallet->fSplitBlock = fSplitBlock;
}

bool WalletModel::getSplitBlock()
{
	return wallet->fSplitBlock;
}

bool WalletModel::isMine(const CBitcoinAddress &address)
{
	return IsMine(*wallet, address.Get());
}
<commit_msg>fix coin lock persisting through shutdown<commit_after>#include "walletmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"

#include "ui_interface.h"
#include "wallet.h"
#include "walletdb.h" // for BackupWallet
#include "base58.h"

#include <QSet>
#include <QTimer>

WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
    QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
    transactionTableModel(0),
    cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
    cachedNumTransactions(0),
    cachedEncryptionStatus(Unencrypted),
    cachedNumBlocks(0)
{
    addressTableModel = new AddressTableModel(wallet, this);
    transactionTableModel = new TransactionTableModel(wallet, this);

    // This timer will be fired repeatedly to update the balance
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

WalletModel::~WalletModel()
{
    unsubscribeFromCoreSignals();
}

qint64 WalletModel::getBalance() const
{
    return wallet->GetBalance();
}

qint64 WalletModel::getUnconfirmedBalance() const
{
    return wallet->GetUnconfirmedBalance();
}

qint64 WalletModel::getStake() const
{
    return wallet->GetStake();
}

qint64 WalletModel::getImmatureBalance() const
{
    return wallet->GetImmatureBalance();
}

int WalletModel::getNumTransactions() const
{
    int numTransactions = 0;
    {
        LOCK(wallet->cs_wallet);
        numTransactions = wallet->mapWallet.size();
    }
    return numTransactions;
}

void WalletModel::updateStatus()
{
    EncryptionStatus newEncryptionStatus = getEncryptionStatus();

    if(cachedEncryptionStatus != newEncryptionStatus)
        emit encryptionStatusChanged(newEncryptionStatus);
}

void WalletModel::pollBalanceChanged()
{
    if(nBestHeight != cachedNumBlocks)
    {
        // Balance and number of transactions might have changed
        cachedNumBlocks = nBestHeight;
        checkBalanceChanged();
    }
}

void WalletModel::checkBalanceChanged()
{
    qint64 newBalance = getBalance();
    qint64 newStake = getStake();
    qint64 newUnconfirmedBalance = getUnconfirmedBalance();
    qint64 newImmatureBalance = getImmatureBalance();

    if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
    {
        cachedBalance = newBalance;
        cachedStake = newStake;
        cachedUnconfirmedBalance = newUnconfirmedBalance;
        cachedImmatureBalance = newImmatureBalance;
        emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
    }
}

void WalletModel::updateTransaction(const QString &hash, int status)
{
    if(transactionTableModel)
        transactionTableModel->updateTransaction(hash, status);

    // Balance and number of transactions might have changed
    checkBalanceChanged();

    int newNumTransactions = getNumTransactions();
    if(cachedNumTransactions != newNumTransactions)
    {
        cachedNumTransactions = newNumTransactions;
        emit numTransactionsChanged(newNumTransactions);
    }
}

void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
{
    if(addressTableModel)
        addressTableModel->updateEntry(address, label, isMine, status);
}

bool WalletModel::validateAddress(const QString &address)
{
    CBitcoinAddress addressParsed(address.toStdString());
    return addressParsed.IsValid();
}

WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, int nSplitBlock, const CCoinControl *coinControl)
{
    qint64 total = 0;
    QSet<QString> setAddress;
    QString hex;

    if(recipients.empty())
    {
        return OK;
    }

    // Pre-check input data for validity
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        if(!validateAddress(rcp.address))
        {
            return InvalidAddress;
        }
        setAddress.insert(rcp.address);

        if(rcp.amount <= 0)
        {
            return InvalidAmount;
        }
        total += rcp.amount;
    }

    if(recipients.size() > setAddress.size())
    {
        return DuplicateAddress;
    }

    int64_t nBalance = 0;
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins, true, coinControl);

    BOOST_FOREACH(const COutput& out, vCoins)
        nBalance += out.tx->vout[out.i].nValue;

    if(total > nBalance)
    {
        return AmountExceedsBalance;
    }

    if((total + nTransactionFee) > nBalance)
    {
        return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
    }

    {
        LOCK2(cs_main, wallet->cs_wallet);

        // Sendmany
        std::vector<std::pair<CScript, int64_t> > vecSend;
        foreach(const SendCoinsRecipient &rcp, recipients)
        {
            CScript scriptPubKey;
            scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
            vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
        }

        CWalletTx wtx;
        CReserveKey keyChange(wallet);
        int64_t nFeeRequired = 0;
        bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nSplitBlock, coinControl);

        if(!fCreated)
        {
            if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
            {
                return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
            }
            return TransactionCreationFailed;
        }
        if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
        {
            return Aborted;
        }
        if(!wallet->CommitTransaction(wtx, keyChange))
        {
            return TransactionCommitFailed;
        }
        hex = QString::fromStdString(wtx.GetHash().GetHex());
    }

    // Add addresses / update labels that we've sent to to the address book
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        std::string strAddress = rcp.address.toStdString();
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        std::string strLabel = rcp.label.toStdString();
        {
            LOCK(wallet->cs_wallet);

            std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest);

            // Check if we have a new address or an updated label
            if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
            {
                wallet->SetAddressBookName(dest, strLabel);
            }
        }
    }

    return SendCoinsReturn(OK, 0, hex);
}

OptionsModel *WalletModel::getOptionsModel()
{
    return optionsModel;
}

AddressTableModel *WalletModel::getAddressTableModel()
{
    return addressTableModel;
}

TransactionTableModel *WalletModel::getTransactionTableModel()
{
    return transactionTableModel;
}

WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
    if(!wallet->IsCrypted())
    {
        return Unencrypted;
    }
    else if(wallet->IsLocked())
    {
        return Locked;
    }
    else
    {
        return Unlocked;
    }
}

bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
    if(encrypted)
    {
        // Encrypt
        return wallet->EncryptWallet(passphrase);
    }
    else
    {
        // Decrypt -- TODO; not supported yet
        return false;
    }
}

bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
{
    if(locked)
    {
        // Lock
        return wallet->Lock();
    }
    else
    {
        // Unlock
        return wallet->Unlock(passPhrase);
    }
}

bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
    bool retval;
    {
        LOCK(wallet->cs_wallet);
        wallet->Lock(); // Make sure wallet is locked before attempting pass change
        retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
    }
    return retval;
}

bool WalletModel::backupWallet(const QString &filename)
{
    return BackupWallet(*wallet, filename.toLocal8Bit().data());
}

// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
    OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
    QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}

static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status)
{
    OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status);
    QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())),
                              Q_ARG(QString, QString::fromStdString(label)),
                              Q_ARG(bool, isMine),
                              Q_ARG(int, status));
}

static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
    OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
    QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(hash.GetHex())),
                              Q_ARG(int, status));
}

void WalletModel::subscribeToCoreSignals()
{
    // Connect signals to wallet
    wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

void WalletModel::unsubscribeFromCoreSignals()
{
    // Disconnect signals from wallet
    wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
    bool was_locked = getEncryptionStatus() == Locked;

    if ((!was_locked) && fWalletUnlockStakingOnly)
    {
       setWalletLocked(true);
       was_locked = getEncryptionStatus() == Locked;

    }
    if(was_locked)
    {
        // Request UI to unlock wallet
        emit requireUnlock();
    }
    // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
    bool valid = getEncryptionStatus() != Locked;

    return UnlockContext(this, valid, was_locked && !fWalletUnlockStakingOnly);
}

WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
        wallet(wallet),
        valid(valid),
        relock(relock)
{
}

WalletModel::UnlockContext::~UnlockContext()
{
    if(valid && relock)
    {
        wallet->setWalletLocked(true);
    }
}

void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
    // Transfer context; old object no longer relocks wallet
    *this = rhs;
    rhs.relock = false;
}

bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
    return wallet->GetPubKey(address, vchPubKeyOut);
}

// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
    BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vOutputs.push_back(out);
    }
}

// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins);
    std::vector<COutPoint> vLockedCoins;

    // add locked coins
    BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vCoins.push_back(out);
    }

    BOOST_FOREACH(const COutput& out, vCoins)
    {
        COutput cout = out;

        while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
        {
            if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
            cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
        }

        CTxDestination address;
        if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
        mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
    }
}

bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
{
	COutPoint outpoint(hash, n);
	return std::find(wallet->lockedcoins.vLockedCoins.begin(), wallet->lockedcoins.vLockedCoins.end(), outpoint) != wallet->lockedcoins.vLockedCoins.end();
}

void WalletModel::lockCoin(COutPoint& outpoint)
{
    wallet->lockedcoins.vLockedCoins.push_back(outpoint);
	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::unlockCoin(COutPoint& outpoint)
{
	for(std::vector<COutPoint>::iterator it = wallet->lockedcoins.vLockedCoins.begin(); it != wallet->lockedcoins.vLockedCoins.end(); it++)
	{
		if (*it == outpoint)
		{
			wallet->lockedcoins.vLockedCoins.erase(it);
			break;
		}
	}

	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::listLockedCoins(std::vector<COutPoint>& vLockedCoins)
{
	vLockedCoins = wallet->lockedcoins.vLockedCoins;
	return;
}

//Information for coin control
void WalletModel::getStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight)
{
	wallet->GetStakeWeightFromValue(nTime, nValue, nWeight);
}

void WalletModel::setSplitBlock(bool fSplitBlock)
{
	wallet->fSplitBlock = fSplitBlock;
}

bool WalletModel::getSplitBlock()
{
	return wallet->fSplitBlock;
}

bool WalletModel::isMine(const CBitcoinAddress &address)
{
	return IsMine(*wallet, address.Get());
}
<|endoftext|>


<commit_before>#include "walletmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"

#include "ui_interface.h"
#include "wallet.h"
#include "walletdb.h" // for BackupWallet
#include "base58.h"

#include <QSet>
#include <QTimer>

WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
    QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
    transactionTableModel(0),
    cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
    cachedNumTransactions(0),
    cachedEncryptionStatus(Unencrypted),
    cachedNumBlocks(0)
{
    addressTableModel = new AddressTableModel(wallet, this);
    transactionTableModel = new TransactionTableModel(wallet, this);

    // This timer will be fired repeatedly to update the balance
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

WalletModel::~WalletModel()
{
    unsubscribeFromCoreSignals();
}

qint64 WalletModel::getBalance() const
{
    return wallet->GetBalance();
}

qint64 WalletModel::getUnconfirmedBalance() const
{
    return wallet->GetUnconfirmedBalance();
}

qint64 WalletModel::getStake() const
{
    return wallet->GetStake();
}

qint64 WalletModel::getImmatureBalance() const
{
    return wallet->GetImmatureBalance();
}

int WalletModel::getNumTransactions() const
{
    int numTransactions = 0;
    {
        LOCK(wallet->cs_wallet);
        numTransactions = wallet->mapWallet.size();
    }
    return numTransactions;
}

void WalletModel::updateStatus()
{
    EncryptionStatus newEncryptionStatus = getEncryptionStatus();

    if(cachedEncryptionStatus != newEncryptionStatus)
        emit encryptionStatusChanged(newEncryptionStatus);
}

void WalletModel::pollBalanceChanged()
{
    if(nBestHeight != cachedNumBlocks)
    {
        // Balance and number of transactions might have changed
        cachedNumBlocks = nBestHeight;
        checkBalanceChanged();
    }
}

void WalletModel::checkBalanceChanged()
{
    qint64 newBalance = getBalance();
    qint64 newStake = getStake();
    qint64 newUnconfirmedBalance = getUnconfirmedBalance();
    qint64 newImmatureBalance = getImmatureBalance();

    if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
    {
        cachedBalance = newBalance;
        cachedStake = newStake;
        cachedUnconfirmedBalance = newUnconfirmedBalance;
        cachedImmatureBalance = newImmatureBalance;
        emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
    }
}

void WalletModel::updateTransaction(const QString &hash, int status)
{
    if(transactionTableModel)
        transactionTableModel->updateTransaction(hash, status);

    // Balance and number of transactions might have changed
    checkBalanceChanged();

    int newNumTransactions = getNumTransactions();
    if(cachedNumTransactions != newNumTransactions)
    {
        cachedNumTransactions = newNumTransactions;
        emit numTransactionsChanged(newNumTransactions);
    }
}

void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
{
    if(addressTableModel)
        addressTableModel->updateEntry(address, label, isMine, status);
}

bool WalletModel::validateAddress(const QString &address)
{
    CBitcoinAddress addressParsed(address.toStdString());
    return addressParsed.IsValid();
}

WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, int nSplitBlock, const CCoinControl *coinControl)
{
    qint64 total = 0;
    QSet<QString> setAddress;
    QString hex;

    if(recipients.empty())
    {
        return OK;
    }

    // Pre-check input data for validity
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        if(!validateAddress(rcp.address))
        {
            return InvalidAddress;
        }
        setAddress.insert(rcp.address);

        if(rcp.amount <= 0)
        {
            return InvalidAmount;
        }
        total += rcp.amount;
    }

    if(recipients.size() > setAddress.size())
    {
        return DuplicateAddress;
    }

    int64_t nBalance = 0;
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins, true, coinControl);

    BOOST_FOREACH(const COutput& out, vCoins)
        nBalance += out.tx->vout[out.i].nValue;

    if(total > nBalance)
    {
        return AmountExceedsBalance;
    }

    if((total + nTransactionFee) > nBalance)
    {
        return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
    }

    {
        LOCK2(cs_main, wallet->cs_wallet);

        // Sendmany
        std::vector<std::pair<CScript, int64_t> > vecSend;
        foreach(const SendCoinsRecipient &rcp, recipients)
        {
            CScript scriptPubKey;
            scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
            vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
        }

        CWalletTx wtx;
        CReserveKey keyChange(wallet);
        int64_t nFeeRequired = 0;
        bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nSplitBlock, coinControl);

        if(!fCreated)
        {
            if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
            {
                return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
            }
            return TransactionCreationFailed;
        }
        if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
        {
            return Aborted;
        }
        if(!wallet->CommitTransaction(wtx, keyChange))
        {
            return TransactionCommitFailed;
        }
        hex = QString::fromStdString(wtx.GetHash().GetHex());
    }

    // Add addresses / update labels that we've sent to to the address book
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        std::string strAddress = rcp.address.toStdString();
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        std::string strLabel = rcp.label.toStdString();
        {
            LOCK(wallet->cs_wallet);

            std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest);

            // Check if we have a new address or an updated label
            if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
            {
                wallet->SetAddressBookName(dest, strLabel);
            }
        }
    }

    return SendCoinsReturn(OK, 0, hex);
}

OptionsModel *WalletModel::getOptionsModel()
{
    return optionsModel;
}

AddressTableModel *WalletModel::getAddressTableModel()
{
    return addressTableModel;
}

TransactionTableModel *WalletModel::getTransactionTableModel()
{
    return transactionTableModel;
}

WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
    if(!wallet->IsCrypted())
    {
        return Unencrypted;
    }
    else if(wallet->IsLocked())
    {
        return Locked;
    }
    else
    {
        return Unlocked;
    }
}

bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
    if(encrypted)
    {
        // Encrypt
        return wallet->EncryptWallet(passphrase);
    }
    else
    {
        // Decrypt -- TODO; not supported yet
        return false;
    }
}

bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase, bool formint)
{
    if(locked)
    {
        // Lock
        return wallet->Lock();
    }
    else
    {
        // Unlock
        bool rc;
		rc = wallet->Unlock(passPhrase);
		if (rc && formint)
			wallet->fWalletUnlockMintOnly=true;
		return rc;

    }
}

bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
    bool retval;
    {
        LOCK(wallet->cs_wallet);
        wallet->Lock(); // Make sure wallet is locked before attempting pass change
        retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
    }
    return retval;
}

bool WalletModel::backupWallet(const QString &filename)
{
    return BackupWallet(*wallet, filename.toLocal8Bit().data());
}

// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
    OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
    QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}

static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status)
{
    OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status);
    QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())),
                              Q_ARG(QString, QString::fromStdString(label)),
                              Q_ARG(bool, isMine),
                              Q_ARG(int, status));
}

static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
    OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
    QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(hash.GetHex())),
                              Q_ARG(int, status));
}

void WalletModel::subscribeToCoreSignals()
{
    // Connect signals to wallet
    wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

void WalletModel::unsubscribeFromCoreSignals()
{
    // Disconnect signals from wallet
    wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
    bool was_locked = getEncryptionStatus() == Locked;

	if ((!was_locked) && wallet->fWalletUnlockMintOnly)
	{
		setWalletLocked(true);
		was_locked = getEncryptionStatus() == Locked;
	}

    if(was_locked)
    {
        // Request UI to unlock wallet
        emit requireUnlock();
    }
    // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
    bool valid = getEncryptionStatus() != Locked;

	return UnlockContext(this, valid, was_locked && !wallet->fWalletUnlockMintOnly);
}

WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
        wallet(wallet),
        valid(valid),
        relock(relock)
{
}

WalletModel::UnlockContext::~UnlockContext()
{
    if(valid && relock)
    {
        wallet->setWalletLocked(true);
    }
}

void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
    // Transfer context; old object no longer relocks wallet
    *this = rhs;
    rhs.relock = false;
}

bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
    return wallet->GetPubKey(address, vchPubKeyOut);
}

// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
    BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vOutputs.push_back(out);
    }
}

// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins);
    std::vector<COutPoint> vLockedCoins;

    // add locked coins
    BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vCoins.push_back(out);
    }

    BOOST_FOREACH(const COutput& out, vCoins)
    {
        COutput cout = out;

        while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
        {
            if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
            cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
        }

        CTxDestination address;
        if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
        mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
    }
}

bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
{
	COutPoint outpoint(hash, n);
	return std::find(wallet->lockedcoins.vLockedCoins.begin(), wallet->lockedcoins.vLockedCoins.end(), outpoint) != wallet->lockedcoins.vLockedCoins.end();
}

void WalletModel::lockCoin(COutPoint& outpoint)
{
    wallet->lockedcoins.vLockedCoins.push_back(outpoint);
	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::unlockCoin(COutPoint& outpoint)
{
	for(std::vector<COutPoint>::iterator it = wallet->lockedcoins.vLockedCoins.begin(); it != wallet->lockedcoins.vLockedCoins.end(); it++)
	{
		if (*it == outpoint)
		{
			wallet->lockedcoins.vLockedCoins.erase(it);
			break;
		}
	}

	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::listLockedCoins(std::vector<COutPoint>& vLockedCoins)
{
	vLockedCoins = wallet->lockedcoins.vLockedCoins;
	return;
}

//Information for coin control
void WalletModel::getStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight)
{
	wallet->GetStakeWeightFromValue(nTime, nValue, nWeight);
}

void WalletModel::setSplitBlock(bool fSplitBlock)
{
	wallet->fSplitBlock = fSplitBlock;
}

bool WalletModel::getSplitBlock()
{
	return wallet->fSplitBlock;
}

bool WalletModel::isMine(const CBitcoinAddress &address)
{
	return IsMine(*wallet, address.Get());
}
<commit_msg>mark MintOnly as false if wallet gets locked<commit_after>#include "walletmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"

#include "ui_interface.h"
#include "wallet.h"
#include "walletdb.h" // for BackupWallet
#include "base58.h"

#include <QSet>
#include <QTimer>

WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
    QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
    transactionTableModel(0),
    cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
    cachedNumTransactions(0),
    cachedEncryptionStatus(Unencrypted),
    cachedNumBlocks(0)
{
    addressTableModel = new AddressTableModel(wallet, this);
    transactionTableModel = new TransactionTableModel(wallet, this);

    // This timer will be fired repeatedly to update the balance
    pollTimer = new QTimer(this);
    connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged()));
    pollTimer->start(MODEL_UPDATE_DELAY);

    subscribeToCoreSignals();
}

WalletModel::~WalletModel()
{
    unsubscribeFromCoreSignals();
}

qint64 WalletModel::getBalance() const
{
    return wallet->GetBalance();
}

qint64 WalletModel::getUnconfirmedBalance() const
{
    return wallet->GetUnconfirmedBalance();
}

qint64 WalletModel::getStake() const
{
    return wallet->GetStake();
}

qint64 WalletModel::getImmatureBalance() const
{
    return wallet->GetImmatureBalance();
}

int WalletModel::getNumTransactions() const
{
    int numTransactions = 0;
    {
        LOCK(wallet->cs_wallet);
        numTransactions = wallet->mapWallet.size();
    }
    return numTransactions;
}

void WalletModel::updateStatus()
{
    EncryptionStatus newEncryptionStatus = getEncryptionStatus();

    if(cachedEncryptionStatus != newEncryptionStatus)
        emit encryptionStatusChanged(newEncryptionStatus);
}

void WalletModel::pollBalanceChanged()
{
    if(nBestHeight != cachedNumBlocks)
    {
        // Balance and number of transactions might have changed
        cachedNumBlocks = nBestHeight;
        checkBalanceChanged();
    }
}

void WalletModel::checkBalanceChanged()
{
    qint64 newBalance = getBalance();
    qint64 newStake = getStake();
    qint64 newUnconfirmedBalance = getUnconfirmedBalance();
    qint64 newImmatureBalance = getImmatureBalance();

    if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
    {
        cachedBalance = newBalance;
        cachedStake = newStake;
        cachedUnconfirmedBalance = newUnconfirmedBalance;
        cachedImmatureBalance = newImmatureBalance;
        emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance);
    }
}

void WalletModel::updateTransaction(const QString &hash, int status)
{
    if(transactionTableModel)
        transactionTableModel->updateTransaction(hash, status);

    // Balance and number of transactions might have changed
    checkBalanceChanged();

    int newNumTransactions = getNumTransactions();
    if(cachedNumTransactions != newNumTransactions)
    {
        cachedNumTransactions = newNumTransactions;
        emit numTransactionsChanged(newNumTransactions);
    }
}

void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
{
    if(addressTableModel)
        addressTableModel->updateEntry(address, label, isMine, status);
}

bool WalletModel::validateAddress(const QString &address)
{
    CBitcoinAddress addressParsed(address.toStdString());
    return addressParsed.IsValid();
}

WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, int nSplitBlock, const CCoinControl *coinControl)
{
    qint64 total = 0;
    QSet<QString> setAddress;
    QString hex;

    if(recipients.empty())
    {
        return OK;
    }

    // Pre-check input data for validity
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        if(!validateAddress(rcp.address))
        {
            return InvalidAddress;
        }
        setAddress.insert(rcp.address);

        if(rcp.amount <= 0)
        {
            return InvalidAmount;
        }
        total += rcp.amount;
    }

    if(recipients.size() > setAddress.size())
    {
        return DuplicateAddress;
    }

    int64_t nBalance = 0;
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins, true, coinControl);

    BOOST_FOREACH(const COutput& out, vCoins)
        nBalance += out.tx->vout[out.i].nValue;

    if(total > nBalance)
    {
        return AmountExceedsBalance;
    }

    if((total + nTransactionFee) > nBalance)
    {
        return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
    }

    {
        LOCK2(cs_main, wallet->cs_wallet);

        // Sendmany
        std::vector<std::pair<CScript, int64_t> > vecSend;
        foreach(const SendCoinsRecipient &rcp, recipients)
        {
            CScript scriptPubKey;
            scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
            vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
        }

        CWalletTx wtx;
        CReserveKey keyChange(wallet);
        int64_t nFeeRequired = 0;
        bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nSplitBlock, coinControl);

        if(!fCreated)
        {
            if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future
            {
                return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
            }
            return TransactionCreationFailed;
        }
        if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
        {
            return Aborted;
        }
        if(!wallet->CommitTransaction(wtx, keyChange))
        {
            return TransactionCommitFailed;
        }
        hex = QString::fromStdString(wtx.GetHash().GetHex());
    }

    // Add addresses / update labels that we've sent to to the address book
    foreach(const SendCoinsRecipient &rcp, recipients)
    {
        std::string strAddress = rcp.address.toStdString();
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        std::string strLabel = rcp.label.toStdString();
        {
            LOCK(wallet->cs_wallet);

            std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest);

            // Check if we have a new address or an updated label
            if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
            {
                wallet->SetAddressBookName(dest, strLabel);
            }
        }
    }

    return SendCoinsReturn(OK, 0, hex);
}

OptionsModel *WalletModel::getOptionsModel()
{
    return optionsModel;
}

AddressTableModel *WalletModel::getAddressTableModel()
{
    return addressTableModel;
}

TransactionTableModel *WalletModel::getTransactionTableModel()
{
    return transactionTableModel;
}

WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
    if(!wallet->IsCrypted())
    {
        return Unencrypted;
    }
    else if(wallet->IsLocked())
    {
        return Locked;
    }
    else
    {
        return Unlocked;
    }
}

bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
    if(encrypted)
    {
        // Encrypt
        return wallet->EncryptWallet(passphrase);
    }
    else
    {
        // Decrypt -- TODO; not supported yet
        return false;
    }
}

bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase, bool formint)
{
    if(locked)
    {
        // Lock
		wallet->fWalletUnlockMintOnly = false;
        return wallet->Lock();
    }
    else
    {
        // Unlock
        bool rc;
		rc = wallet->Unlock(passPhrase);
		if (rc && formint)
			wallet->fWalletUnlockMintOnly=true;
		return rc;

    }
}

bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
    bool retval;
    {
        LOCK(wallet->cs_wallet);
        wallet->Lock(); // Make sure wallet is locked before attempting pass change
        retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
    }
    return retval;
}

bool WalletModel::backupWallet(const QString &filename)
{
    return BackupWallet(*wallet, filename.toLocal8Bit().data());
}

// Handlers for core signals
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
{
    OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
    QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
}

static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status)
{
    OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status);
    QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())),
                              Q_ARG(QString, QString::fromStdString(label)),
                              Q_ARG(bool, isMine),
                              Q_ARG(int, status));
}

static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
{
    OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
    QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
                              Q_ARG(QString, QString::fromStdString(hash.GetHex())),
                              Q_ARG(int, status));
}

void WalletModel::subscribeToCoreSignals()
{
    // Connect signals to wallet
    wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

void WalletModel::unsubscribeFromCoreSignals()
{
    // Disconnect signals from wallet
    wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
    wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
    wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
}

// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
    bool was_locked = getEncryptionStatus() == Locked;

	if ((!was_locked) && wallet->fWalletUnlockMintOnly)
	{
		setWalletLocked(true);
		was_locked = getEncryptionStatus() == Locked;
	}

    if(was_locked)
    {
        // Request UI to unlock wallet
        emit requireUnlock();
    }
    // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
    bool valid = getEncryptionStatus() != Locked;

	return UnlockContext(this, valid, was_locked && !wallet->fWalletUnlockMintOnly);
}

WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
        wallet(wallet),
        valid(valid),
        relock(relock)
{
}

WalletModel::UnlockContext::~UnlockContext()
{
    if(valid && relock)
    {
        wallet->setWalletLocked(true);
    }
}

void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
    // Transfer context; old object no longer relocks wallet
    *this = rhs;
    rhs.relock = false;
}

bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
    return wallet->GetPubKey(address, vchPubKeyOut);
}

// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
    BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vOutputs.push_back(out);
    }
}

// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
    std::vector<COutput> vCoins;
    wallet->AvailableCoins(vCoins);
    std::vector<COutPoint> vLockedCoins;

    // add locked coins
    BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
    {
        if (!wallet->mapWallet.count(outpoint.hash)) continue;
        int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
        if (nDepth < 0) continue;
        COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
        vCoins.push_back(out);
    }

    BOOST_FOREACH(const COutput& out, vCoins)
    {
        COutput cout = out;

        while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
        {
            if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
            cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
        }

        CTxDestination address;
        if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
        mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
    }
}

bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
{
	COutPoint outpoint(hash, n);
	return std::find(wallet->lockedcoins.vLockedCoins.begin(), wallet->lockedcoins.vLockedCoins.end(), outpoint) != wallet->lockedcoins.vLockedCoins.end();
}

void WalletModel::lockCoin(COutPoint& outpoint)
{
    wallet->lockedcoins.vLockedCoins.push_back(outpoint);
	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::unlockCoin(COutPoint& outpoint)
{
	for(std::vector<COutPoint>::iterator it = wallet->lockedcoins.vLockedCoins.begin(); it != wallet->lockedcoins.vLockedCoins.end(); it++)
	{
		if (*it == outpoint)
		{
			wallet->lockedcoins.vLockedCoins.erase(it);
			break;
		}
	}

	CWalletDB walletdb(wallet->strWalletFile);
	walletdb.WriteLockedCoins(wallet->lockedcoins);
	return;
}

void WalletModel::listLockedCoins(std::vector<COutPoint>& vLockedCoins)
{
	vLockedCoins = wallet->lockedcoins.vLockedCoins;
	return;
}

//Information for coin control
void WalletModel::getStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight)
{
	wallet->GetStakeWeightFromValue(nTime, nValue, nWeight);
}

void WalletModel::setSplitBlock(bool fSplitBlock)
{
	wallet->fSplitBlock = fSplitBlock;
}

bool WalletModel::getSplitBlock()
{
	return wallet->fSplitBlock;
}

bool WalletModel::isMine(const CBitcoinAddress &address)
{
	return IsMine(*wallet, address.Get());
}
<|endoftext|>