<commit_before>/*
 * OXT - OS eXtensions for boosT
 * Provides important functionality necessary for writing robust server software.
 *
 * Copyright (c) 2008 Phusion
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef _OXT_SYSTEM_CALLS_HPP_
#define _OXT_SYSTEM_CALLS_HPP_

#include <boost/thread/tss.hpp>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <cstdio>
#include <ctime>
#include <cassert>

/**
 * Support for interruption of blocking system calls and C library calls
 *
 * This file provides a framework for writing multithreading code that can
 * be interrupted, even when blocked on system calls or C library calls.
 *
 * One must first call oxt::setup_syscall_interruption_support().
 * Then one may use the functions in oxt::syscalls as drop-in replacements
 * for system calls or C library functions. These functions throw
 * boost::thread_interrupted upon interruption.
 *
 * System call interruption is disabled by default. In other words: the
 * replacement functions in this file don't throw boost::thread_interrupted.
 * You can enable or disable system call interruption in the current scope
 * by creating instances of boost::this_thread::enable_syscall_interruption
 * and similar objects. This is similar to Boost thread interruption.
 *
 *
How to interrupt

 * Generally, oxt::thread::interrupt() and oxt::thread::interrupt_and_join()
 * should be used for interrupting threads. These methods will interrupt
 * the thread at all Boost interruption points, as well as system calls that
 * are caled through the oxt::syscalls namespace. Do *not* use
 * boost::thread::interrupt, because that will not honor system calls as
 * interruption points.
 *
 * Under the hood, system calls are interrupted by sending a signal to the
 * to a specific thread (note: sending a signal to a process will deliver the
 * signal to the main thread).
 *
 * Any signal will do, but of course, one should only send a signal whose
 * signal handler doesn't do undesirable things (such as aborting the entire
 * program). That's why it's generally recommended that you only use
 * oxt::INTERRUPTION_SIGNAL to interrupt system calls, because
 * oxt::setup_syscall_interruption_support() installs an "nice" signal
 * handler for that signal (though you should of course use
 * oxt::thread::interrupt() instead of sending signals whenever
 * possible).
 *
 * Note that sending a signal once may not interrupt the thread, because
 * the thread may not be calling a system call at the time the signal was
 * received. So one must keep sending signals periodically until the
 * thread has quit.
 *
 * @warning
 * After oxt::setup_syscall_interruption_support() is called, sending a signal
 * will cause system calls to return with an EINTR error. The oxt::syscall
 * functions will automatically take care of this, but if you're calling any
 * system calls without using that namespace, then you should check for and
 * take care of EINTR errors.
 */

// This is one of the things that Java is good at and C++ sucks at. Sigh...

namespace oxt {
	static const int INTERRUPTION_SIGNAL = SIGUSR2;

	/**
	 * Setup system call interruption support.
	 * This function may only be called once. It installs a signal handler
	 * for INTERRUPTION_SIGNAL, so one should not install a different signal
	 * handler for that signal after calling this function.
	 *
	 * @warning
	 * After oxt::setup_syscall_interruption_support() is called, sending a signal
	 * will cause system calls to return with an EINTR error. The oxt::syscall
	 * functions will automatically take care of this, but if you're calling any
	 * system calls without using that namespace, then you should check for and
	 * take care of EINTR errors.
	 */
	void setup_syscall_interruption_support();

	/**
	 * System call and C library call wrappers with interruption support.
	 * These functions are interruption points, i.e. they throw
	 * boost::thread_interrupted whenever the calling thread is interrupted
	 * by oxt::thread::interrupt() or oxt::thread::interrupt_and_join().
	 */
	namespace syscalls {
		ssize_t read(int fd, void *buf, size_t count);
		ssize_t write(int fd, const void *buf, size_t count);
		int close(int fd);

		int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
		int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
		int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
		int listen(int sockfd, int backlog);
		int socket(int domain, int type, int protocol);
		int socketpair(int d, int type, int protocol, int sv[2]);
		ssize_t recvmsg(int s, struct msghdr *msg, int flags);
		ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
		int setsockopt(int s, int level, int optname, const void *optval,
			socklen_t optlen);
		int shutdown(int s, int how);

		FILE *fopen(const char *path, const char *mode);
		int fclose(FILE *fp);
		int unlink(const char *pathname);

		time_t time(time_t *t);
		int usleep(useconds_t usec);
		int nanosleep(const struct timespec *req, struct timespec *rem);

		pid_t fork();
		int kill(pid_t pid, int sig);
		pid_t waitpid(pid_t pid, int *status, int options);
	}

} // namespace oxt

namespace boost {
namespace this_thread {

	/**
	 * @intern
	 */
	extern thread_specific_ptr<bool> _syscalls_interruptable;

	/**
	 * Check whether system calls should be interruptable in
	 * the calling thread.
	 */
	bool syscalls_interruptable();

	class restore_syscall_interruption;

	/**
	 * Create this struct on the stack to temporarily enable system
	 * call interruption, until the object goes out of scope.
	 */
	class enable_syscall_interruption {
	private:
		bool last_value;
	public:
		enable_syscall_interruption() {
			if (_syscalls_interruptable.get() == NULL) {
				last_value = true;
				_syscalls_interruptable.reset(new bool(true));
			} else {
				last_value = *_syscalls_interruptable;
				*_syscalls_interruptable = true;
			}
		}

		~enable_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

	/**
	 * Create this struct on the stack to temporarily disable system
	 * call interruption, until the object goes out of scope.
	 * While system call interruption is disabled, the functions in
	 * InterruptableCalls will try until the return code is not EINTR.
	 */
	class disable_syscall_interruption {
	private:
		friend class restore_syscall_interruption;
		bool last_value;
	public:
		disable_syscall_interruption() {
			if (_syscalls_interruptable.get() == NULL) {
				last_value = true;
				_syscalls_interruptable.reset(new bool(false));
			} else {
				last_value = *_syscalls_interruptable;
				*_syscalls_interruptable = false;
			}
		}

		~disable_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

	/**
	 * Creating an object of this class on the stack will restore the
	 * system call interruption state to what it was before.
	 */
	class restore_syscall_interruption {
	private:
		int last_value;
	public:
		restore_syscall_interruption(const disable_syscall_interruption &intr) {
			assert(_syscalls_interruptable.get() != NULL);
			last_value = *_syscalls_interruptable;
			*_syscalls_interruptable = intr.last_value;
		}

		~restore_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

} // namespace this_thread
} // namespace boost

#endif /* _OXT_SYSTEM_CALLS_HPP_ */

<commit_msg>Update outdated OXT documentation.<commit_after>/*
 * OXT - OS eXtensions for boosT
 * Provides important functionality necessary for writing robust server software.
 *
 * Copyright (c) 2008 Phusion
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef _OXT_SYSTEM_CALLS_HPP_
#define _OXT_SYSTEM_CALLS_HPP_

#include <boost/thread/tss.hpp>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <cstdio>
#include <ctime>
#include <cassert>

/**
 * Support for interruption of blocking system calls and C library calls
 *
 * This file provides a framework for writing multithreading code that can
 * be interrupted, even when blocked on system calls or C library calls.
 *
 * One must first call oxt::setup_syscall_interruption_support().
 * Then one may use the functions in oxt::syscalls as drop-in replacements
 * for system calls or C library functions. These functions throw
 * boost::thread_interrupted upon interruption.
 *
 * Once setup_syscall_interruption_support() has been called, system call
 * interruption is enabled by default. You can enable or disable system call
 * interruption in the current scope by creating instances of
 * boost::this_thread::enable_syscall_interruption or
 * boost::this_thread::disable_syscall_interruption, respectively. When system
 * call interruption is disabled, the oxt::syscall wrapper functions will
 * ignore interruption requests. This is similar to Boost thread interruption.
 *
 *
How to interrupt

 * Generally, oxt::thread::interrupt() and oxt::thread::interrupt_and_join()
 * should be used for interrupting threads. These methods will interrupt
 * the thread at all Boost interruption points, as well as system calls that
 * are caled through the oxt::syscalls namespace. Do *not* use
 * boost::thread::interrupt, because that will not honor system calls as
 * interruption points.
 *
 * Under the hood, system calls are interrupted by sending a signal to the
 * to a specific thread (note: sending a signal to a process will deliver the
 * signal to the main thread).
 *
 * Any signal will do, but of course, one should only send a signal whose
 * signal handler doesn't do undesirable things (such as aborting the entire
 * program). That's why it's generally recommended that you only use
 * oxt::INTERRUPTION_SIGNAL to interrupt system calls, because
 * oxt::setup_syscall_interruption_support() installs an "nice" signal
 * handler for that signal (though you should of course use
 * oxt::thread::interrupt() instead of sending signals whenever
 * possible).
 *
 * Note that sending a signal once may not interrupt the thread, because
 * the thread may not be calling a system call at the time the signal was
 * received. So one must keep sending signals periodically until the
 * thread has quit.
 *
 * @warning
 * After oxt::setup_syscall_interruption_support() is called, sending a signal
 * will cause system calls to return with an EINTR error. The oxt::syscall
 * functions will automatically take care of this, but if you're calling any
 * system calls without using that namespace, then you should check for and
 * take care of EINTR errors.
 */

// This is one of the things that Java is good at and C++ sucks at. Sigh...

namespace oxt {
	static const int INTERRUPTION_SIGNAL = SIGUSR2;

	/**
	 * Setup system call interruption support.
	 * This function may only be called once. It installs a signal handler
	 * for INTERRUPTION_SIGNAL, so one should not install a different signal
	 * handler for that signal after calling this function.
	 *
	 * @warning
	 * After oxt::setup_syscall_interruption_support() is called, sending a signal
	 * will cause system calls to return with an EINTR error. The oxt::syscall
	 * functions will automatically take care of this, but if you're calling any
	 * system calls without using that namespace, then you should check for and
	 * take care of EINTR errors.
	 */
	void setup_syscall_interruption_support();

	/**
	 * System call and C library call wrappers with interruption support.
	 * These functions are interruption points, i.e. they throw
	 * boost::thread_interrupted whenever the calling thread is interrupted
	 * by oxt::thread::interrupt() or oxt::thread::interrupt_and_join().
	 */
	namespace syscalls {
		ssize_t read(int fd, void *buf, size_t count);
		ssize_t write(int fd, const void *buf, size_t count);
		int close(int fd);

		int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
		int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
		int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
		int listen(int sockfd, int backlog);
		int socket(int domain, int type, int protocol);
		int socketpair(int d, int type, int protocol, int sv[2]);
		ssize_t recvmsg(int s, struct msghdr *msg, int flags);
		ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
		int setsockopt(int s, int level, int optname, const void *optval,
			socklen_t optlen);
		int shutdown(int s, int how);

		FILE *fopen(const char *path, const char *mode);
		int fclose(FILE *fp);
		int unlink(const char *pathname);

		time_t time(time_t *t);
		int usleep(useconds_t usec);
		int nanosleep(const struct timespec *req, struct timespec *rem);

		pid_t fork();
		int kill(pid_t pid, int sig);
		pid_t waitpid(pid_t pid, int *status, int options);
	}

} // namespace oxt

namespace boost {
namespace this_thread {

	/**
	 * @intern
	 */
	extern thread_specific_ptr<bool> _syscalls_interruptable;

	/**
	 * Check whether system calls should be interruptable in
	 * the calling thread.
	 */
	bool syscalls_interruptable();

	class restore_syscall_interruption;

	/**
	 * Create this struct on the stack to temporarily enable system
	 * call interruption, until the object goes out of scope.
	 */
	class enable_syscall_interruption {
	private:
		bool last_value;
	public:
		enable_syscall_interruption() {
			if (_syscalls_interruptable.get() == NULL) {
				last_value = true;
				_syscalls_interruptable.reset(new bool(true));
			} else {
				last_value = *_syscalls_interruptable;
				*_syscalls_interruptable = true;
			}
		}

		~enable_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

	/**
	 * Create this struct on the stack to temporarily disable system
	 * call interruption, until the object goes out of scope.
	 * While system call interruption is disabled, the functions in
	 * InterruptableCalls will try until the return code is not EINTR.
	 */
	class disable_syscall_interruption {
	private:
		friend class restore_syscall_interruption;
		bool last_value;
	public:
		disable_syscall_interruption() {
			if (_syscalls_interruptable.get() == NULL) {
				last_value = true;
				_syscalls_interruptable.reset(new bool(false));
			} else {
				last_value = *_syscalls_interruptable;
				*_syscalls_interruptable = false;
			}
		}

		~disable_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

	/**
	 * Creating an object of this class on the stack will restore the
	 * system call interruption state to what it was before.
	 */
	class restore_syscall_interruption {
	private:
		int last_value;
	public:
		restore_syscall_interruption(const disable_syscall_interruption &intr) {
			assert(_syscalls_interruptable.get() != NULL);
			last_value = *_syscalls_interruptable;
			*_syscalls_interruptable = intr.last_value;
		}

		~restore_syscall_interruption() {
			*_syscalls_interruptable = last_value;
		}
	};

} // namespace this_thread
} // namespace boost

#endif /* _OXT_SYSTEM_CALLS_HPP_ */

<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>

#include <vector>
#include <utility>

#include <mesos/master/detector.hpp>

#include <mesos/mesos.hpp>

#include <mesos/module/anonymous.hpp>

#include <mesos/slave/resource_estimator.hpp>

#include <process/owned.hpp>

#include <stout/check.hpp>
#include <stout/flags.hpp>
#include <stout/hashset.hpp>
#include <stout/nothing.hpp>
#include <stout/os.hpp>
#include <stout/stringify.hpp>
#include <stout/try.hpp>

#include "common/build.hpp"

#include "hook/manager.hpp"

#ifdef __linux__
#include "linux/systemd.hpp"
#endif // __linux__

#include "logging/logging.hpp"

#include "messages/flags.hpp"
#include "messages/messages.hpp"

#include "module/manager.hpp"

#include "slave/gc.hpp"
#include "slave/slave.hpp"
#include "slave/status_update_manager.hpp"

#include "version/version.hpp"

using namespace mesos::internal;
using namespace mesos::internal::slave;

using mesos::master::detector::MasterDetector;

using mesos::modules::Anonymous;
using mesos::modules::ModuleManager;

using mesos::master::detector::MasterDetector;

using mesos::slave::QoSController;
using mesos::slave::ResourceEstimator;

using mesos::SlaveInfo;

using process::Owned;

using process::firewall::DisabledEndpointsFirewallRule;
using process::firewall::FirewallRule;

using std::cerr;
using std::cout;
using std::endl;
using std::move;
using std::string;
using std::vector;

void version()
{
  cout << "mesos" << " " << MESOS_VERSION << endl;
}

int main(int argc, char** argv)
{
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  slave::Flags flags;

  // The following flags are executable specific (e.g., since we only
  // have one instance of libprocess per execution, we only want to
  // advertise the IP and port option once, here).
  Option<string> ip;
  flags.add(&ip,
            "ip",
            "IP address to listen on. This cannot be used in conjunction\n"
            "with `--ip_discovery_command`.");

  uint16_t port;
  flags.add(&port,
            "port",
            "Port to listen on.",
            SlaveInfo().port());

  Option<string> advertise_ip;
  flags.add(&advertise_ip,
            "advertise_ip",
            "IP address advertised to reach this Mesos agent.\n"
            "The agent does not bind to this IP address.\n"
            "However, this IP address may be used to access this agent.");

  Option<string> advertise_port;
  flags.add(&advertise_port,
            "advertise_port",
            "Port advertised to reach this Mesos agent (along with\n"
            "`advertise_ip`). The agent does not bind to this port.\n"
            "However, this port (along with `advertise_ip`) may be used to\n"
            "access this agent.");

  Option<string> master;
  flags.add(&master,
            "master",
            "May be one of:\n"
            "  `host:port`\n"
            "  `zk://host1:port1,host2:port2,.../path`\n"
            "  `zk://username:password@host1:port1,host2:port2,.../path`\n"
            "  `file:///path/to/file` (where file contains one of the above)");

  // Optional IP discover script that will set the slave's IP.
  // If set, its output is expected to be a valid parseable IP string.
  Option<string> ip_discovery_command;
  flags.add(&ip_discovery_command,
            "ip_discovery_command",
            "Optional IP discovery binary: if set, it is expected to emit\n"
            "the IP address which the agent will try to bind to.\n"
            "Cannot be used in conjunction with `--ip`.");

  Try<Nothing> load = flags.load("MESOS_", argc, argv);

  // TODO(marco): this pattern too should be abstracted away
  // in FlagsBase; I have seen it at least 15 times.
  if (load.isError()) {
    cerr << flags.usage(load.error()) << endl;
    return EXIT_FAILURE;
  }

  if (flags.help) {
    cout << flags.usage() << endl;
    return EXIT_SUCCESS;
  }

  if (flags.version) {
    version();
    return EXIT_SUCCESS;
  }

  if (master.isNone() && flags.master_detector.isNone()) {
    cerr << flags.usage("Missing required option `--master` or "
                        "`--master_detector`.") << endl;
    return EXIT_FAILURE;
  }

  if (master.isSome() && flags.master_detector.isSome()) {
    cerr << flags.usage("Only one of --master or --master_detector options "
                        "should be specified.");
    return EXIT_FAILURE;
  }

  // Initialize modules. Note that since other subsystems may depend
  // upon modules, we should initialize modules before anything else.
  if (flags.modules.isSome()) {
    Try<Nothing> result = ModuleManager::load(flags.modules.get());
    if (result.isError()) {
      EXIT(EXIT_FAILURE) << "Error loading modules: " << result.error();
    }
  }

  // Initialize hooks.
  if (flags.hooks.isSome()) {
    Try<Nothing> result = HookManager::initialize(flags.hooks.get());
    if (result.isError()) {
      EXIT(EXIT_FAILURE) << "Error installing hooks: " << result.error();
    }
  }

  // Initialize libprocess.
  if (ip_discovery_command.isSome() && ip.isSome()) {
    EXIT(EXIT_FAILURE) << flags.usage(
        "Only one of `--ip` or `--ip_discovery_command` should be specified");
  }

  if (ip_discovery_command.isSome()) {
    Try<string> ipAddress = os::shell(ip_discovery_command.get());

    if (ipAddress.isError()) {
      EXIT(EXIT_FAILURE) << ipAddress.error();
    }

    os::setenv("LIBPROCESS_IP", strings::trim(ipAddress.get()));
  } else if (ip.isSome()) {
    os::setenv("LIBPROCESS_IP", ip.get());
  }

  os::setenv("LIBPROCESS_PORT", stringify(port));

  if (advertise_ip.isSome()) {
    os::setenv("LIBPROCESS_ADVERTISE_IP", advertise_ip.get());
  }

  if (advertise_port.isSome()) {
    os::setenv("LIBPROCESS_ADVERTISE_PORT", advertise_port.get());
  }

  const string id = process::ID::generate("slave"); // Process ID.

  process::initialize(id);

  logging::initialize(argv[0], flags, true); // Catch signals.

  spawn(new VersionProcess(), true);

  LOG(INFO) << "Build: " << build::DATE << " by " << build::USER;

  LOG(INFO) << "Version: " << MESOS_VERSION;

  if (build::GIT_TAG.isSome()) {
    LOG(INFO) << "Git tag: " << build::GIT_TAG.get();
  }

  if (build::GIT_SHA.isSome()) {
    LOG(INFO) << "Git SHA: " << build::GIT_SHA.get();
  }

  Fetcher fetcher;

#ifdef __linux__
  // Initialize systemd if it exists.
  if (systemd::exists() && flags.systemd_enable_support) {
    LOG(INFO) << "Inializing systemd state";

    systemd::Flags systemdFlags;
    systemdFlags.enabled = flags.systemd_enable_support;
    systemdFlags.runtime_directory = flags.systemd_runtime_directory;
    systemdFlags.cgroups_hierarchy = flags.cgroups_hierarchy;

    Try<Nothing> initialize = systemd::initialize(systemdFlags);
    if (initialize.isError()) {
      EXIT(EXIT_FAILURE)
        << "Failed to initialize systemd: " + initialize.error();
    }
  }
#endif // __linux__

  Try<Containerizer*> containerizer =
    Containerizer::create(flags, false, &fetcher);

  if (containerizer.isError()) {
    EXIT(EXIT_FAILURE)
      << "Failed to create a containerizer: " << containerizer.error();
  }

  Try<MasterDetector*> detector_ = MasterDetector::create(
      master, flags.master_detector);

  if (detector_.isError()) {
    EXIT(EXIT_FAILURE)
      << "Failed to create a master detector: " << detector_.error();
  }

  MasterDetector* detector = detector_.get();

  if (flags.firewall_rules.isSome()) {
    vector<Owned<FirewallRule>> rules;

    const Firewall firewall = flags.firewall_rules.get();

    if (firewall.has_disabled_endpoints()) {
      hashset<string> paths;

      foreach (const string& path, firewall.disabled_endpoints().paths()) {
        paths.insert(path);
      }

      rules.emplace_back(new DisabledEndpointsFirewallRule(paths));
    }

    process::firewall::install(move(rules));
  }

  // Create anonymous modules.
  foreach (const string& name, ModuleManager::find<Anonymous>()) {
    Try<Anonymous*> create = ModuleManager::create<Anonymous>(name);
    if (create.isError()) {
      EXIT(EXIT_FAILURE)
        << "Failed to create anonymous module named '" << name << "'";
    }

    // We don't bother keeping around the pointer to this anonymous
    // module, when we exit that will effectively free it's memory.
    //
    // TODO(benh): We might want to add explicit finalization (and
    // maybe explicit initialization too) in order to let the module
    // do any housekeeping necessary when the slave is cleanly
    // terminating.
  }

  Files files(DEFAULT_HTTP_AUTHENTICATION_REALM);
  GarbageCollector gc;
  StatusUpdateManager statusUpdateManager(flags);

  Try<ResourceEstimator*> resourceEstimator =
    ResourceEstimator::create(flags.resource_estimator);

  if (resourceEstimator.isError()) {
    cerr << "Failed to create resource estimator: "
         << resourceEstimator.error() << endl;
    return EXIT_FAILURE;
  }

  Try<QoSController*> qosController =
    QoSController::create(flags.qos_controller);

  if (qosController.isError()) {
    cerr << "Failed to create QoS Controller: "
         << qosController.error() << endl;
    return EXIT_FAILURE;
  }

  LOG(INFO) << "Starting Mesos agent";

  Slave* slave = new Slave(
      id,
      flags,
      detector,
      containerizer.get(),
      &files,
      &gc,
      &statusUpdateManager,
      resourceEstimator.get(),
      qosController.get());

  process::spawn(slave);
  process::wait(slave->self());

  delete slave;

  delete resourceEstimator.get();

  delete qosController.get();

  delete detector;

  delete containerizer.get();

  return EXIT_SUCCESS;
}
<commit_msg>Fixed slave to initialize libprocess before modules.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdint.h>

#include <vector>
#include <utility>

#include <mesos/master/detector.hpp>

#include <mesos/mesos.hpp>

#include <mesos/module/anonymous.hpp>

#include <mesos/slave/resource_estimator.hpp>

#include <process/owned.hpp>

#include <stout/check.hpp>
#include <stout/flags.hpp>
#include <stout/hashset.hpp>
#include <stout/nothing.hpp>
#include <stout/os.hpp>
#include <stout/stringify.hpp>
#include <stout/try.hpp>

#include "common/build.hpp"

#include "hook/manager.hpp"

#ifdef __linux__
#include "linux/systemd.hpp"
#endif // __linux__

#include "logging/logging.hpp"

#include "messages/flags.hpp"
#include "messages/messages.hpp"

#include "module/manager.hpp"

#include "slave/gc.hpp"
#include "slave/slave.hpp"
#include "slave/status_update_manager.hpp"

#include "version/version.hpp"

using namespace mesos::internal;
using namespace mesos::internal::slave;

using mesos::master::detector::MasterDetector;

using mesos::modules::Anonymous;
using mesos::modules::ModuleManager;

using mesos::master::detector::MasterDetector;

using mesos::slave::QoSController;
using mesos::slave::ResourceEstimator;

using mesos::SlaveInfo;

using process::Owned;

using process::firewall::DisabledEndpointsFirewallRule;
using process::firewall::FirewallRule;

using std::cerr;
using std::cout;
using std::endl;
using std::move;
using std::string;
using std::vector;

void version()
{
  cout << "mesos" << " " << MESOS_VERSION << endl;
}

int main(int argc, char** argv)
{
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  slave::Flags flags;

  // The following flags are executable specific (e.g., since we only
  // have one instance of libprocess per execution, we only want to
  // advertise the IP and port option once, here).
  Option<string> ip;
  flags.add(&ip,
            "ip",
            "IP address to listen on. This cannot be used in conjunction\n"
            "with `--ip_discovery_command`.");

  uint16_t port;
  flags.add(&port,
            "port",
            "Port to listen on.",
            SlaveInfo().port());

  Option<string> advertise_ip;
  flags.add(&advertise_ip,
            "advertise_ip",
            "IP address advertised to reach this Mesos agent.\n"
            "The agent does not bind to this IP address.\n"
            "However, this IP address may be used to access this agent.");

  Option<string> advertise_port;
  flags.add(&advertise_port,
            "advertise_port",
            "Port advertised to reach this Mesos agent (along with\n"
            "`advertise_ip`). The agent does not bind to this port.\n"
            "However, this port (along with `advertise_ip`) may be used to\n"
            "access this agent.");

  Option<string> master;
  flags.add(&master,
            "master",
            "May be one of:\n"
            "  `host:port`\n"
            "  `zk://host1:port1,host2:port2,.../path`\n"
            "  `zk://username:password@host1:port1,host2:port2,.../path`\n"
            "  `file:///path/to/file` (where file contains one of the above)");

  // Optional IP discover script that will set the slave's IP.
  // If set, its output is expected to be a valid parseable IP string.
  Option<string> ip_discovery_command;
  flags.add(&ip_discovery_command,
            "ip_discovery_command",
            "Optional IP discovery binary: if set, it is expected to emit\n"
            "the IP address which the agent will try to bind to.\n"
            "Cannot be used in conjunction with `--ip`.");

  Try<Nothing> load = flags.load("MESOS_", argc, argv);

  // TODO(marco): this pattern too should be abstracted away
  // in FlagsBase; I have seen it at least 15 times.
  if (load.isError()) {
    cerr << flags.usage(load.error()) << endl;
    return EXIT_FAILURE;
  }

  if (flags.help) {
    cout << flags.usage() << endl;
    return EXIT_SUCCESS;
  }

  if (flags.version) {
    version();
    return EXIT_SUCCESS;
  }

  if (master.isNone() && flags.master_detector.isNone()) {
    cerr << flags.usage("Missing required option `--master` or "
                        "`--master_detector`.") << endl;
    return EXIT_FAILURE;
  }

  if (master.isSome() && flags.master_detector.isSome()) {
    cerr << flags.usage("Only one of --master or --master_detector options "
                        "should be specified.");
    return EXIT_FAILURE;
  }

  // Initialize libprocess.
  if (ip_discovery_command.isSome() && ip.isSome()) {
    EXIT(EXIT_FAILURE) << flags.usage(
        "Only one of `--ip` or `--ip_discovery_command` should be specified");
  }

  if (ip_discovery_command.isSome()) {
    Try<string> ipAddress = os::shell(ip_discovery_command.get());

    if (ipAddress.isError()) {
      EXIT(EXIT_FAILURE) << ipAddress.error();
    }

    os::setenv("LIBPROCESS_IP", strings::trim(ipAddress.get()));
  } else if (ip.isSome()) {
    os::setenv("LIBPROCESS_IP", ip.get());
  }

  os::setenv("LIBPROCESS_PORT", stringify(port));

  if (advertise_ip.isSome()) {
    os::setenv("LIBPROCESS_ADVERTISE_IP", advertise_ip.get());
  }

  if (advertise_port.isSome()) {
    os::setenv("LIBPROCESS_ADVERTISE_PORT", advertise_port.get());
  }

  const string id = process::ID::generate("slave"); // Process ID.

  process::initialize(id);

  logging::initialize(argv[0], flags, true); // Catch signals.

  // Initialize modules. Note that since other subsystems may depend
  // upon modules, we should initialize modules before anything else.
  if (flags.modules.isSome()) {
    Try<Nothing> result = ModuleManager::load(flags.modules.get());
    if (result.isError()) {
      EXIT(EXIT_FAILURE) << "Error loading modules: " << result.error();
    }
  }

  // Initialize hooks.
  if (flags.hooks.isSome()) {
    Try<Nothing> result = HookManager::initialize(flags.hooks.get());
    if (result.isError()) {
      EXIT(EXIT_FAILURE) << "Error installing hooks: " << result.error();
    }
  }

  spawn(new VersionProcess(), true);

  LOG(INFO) << "Build: " << build::DATE << " by " << build::USER;

  LOG(INFO) << "Version: " << MESOS_VERSION;

  if (build::GIT_TAG.isSome()) {
    LOG(INFO) << "Git tag: " << build::GIT_TAG.get();
  }

  if (build::GIT_SHA.isSome()) {
    LOG(INFO) << "Git SHA: " << build::GIT_SHA.get();
  }

  Fetcher fetcher;

#ifdef __linux__
  // Initialize systemd if it exists.
  if (systemd::exists() && flags.systemd_enable_support) {
    LOG(INFO) << "Inializing systemd state";

    systemd::Flags systemdFlags;
    systemdFlags.enabled = flags.systemd_enable_support;
    systemdFlags.runtime_directory = flags.systemd_runtime_directory;
    systemdFlags.cgroups_hierarchy = flags.cgroups_hierarchy;

    Try<Nothing> initialize = systemd::initialize(systemdFlags);
    if (initialize.isError()) {
      EXIT(EXIT_FAILURE)
        << "Failed to initialize systemd: " + initialize.error();
    }
  }
#endif // __linux__

  Try<Containerizer*> containerizer =
    Containerizer::create(flags, false, &fetcher);

  if (containerizer.isError()) {
    EXIT(EXIT_FAILURE)
      << "Failed to create a containerizer: " << containerizer.error();
  }

  Try<MasterDetector*> detector_ = MasterDetector::create(
      master, flags.master_detector);

  if (detector_.isError()) {
    EXIT(EXIT_FAILURE)
      << "Failed to create a master detector: " << detector_.error();
  }

  MasterDetector* detector = detector_.get();

  if (flags.firewall_rules.isSome()) {
    vector<Owned<FirewallRule>> rules;

    const Firewall firewall = flags.firewall_rules.get();

    if (firewall.has_disabled_endpoints()) {
      hashset<string> paths;

      foreach (const string& path, firewall.disabled_endpoints().paths()) {
        paths.insert(path);
      }

      rules.emplace_back(new DisabledEndpointsFirewallRule(paths));
    }

    process::firewall::install(move(rules));
  }

  // Create anonymous modules.
  foreach (const string& name, ModuleManager::find<Anonymous>()) {
    Try<Anonymous*> create = ModuleManager::create<Anonymous>(name);
    if (create.isError()) {
      EXIT(EXIT_FAILURE)
        << "Failed to create anonymous module named '" << name << "'";
    }

    // We don't bother keeping around the pointer to this anonymous
    // module, when we exit that will effectively free it's memory.
    //
    // TODO(benh): We might want to add explicit finalization (and
    // maybe explicit initialization too) in order to let the module
    // do any housekeeping necessary when the slave is cleanly
    // terminating.
  }

  Files files(DEFAULT_HTTP_AUTHENTICATION_REALM);
  GarbageCollector gc;
  StatusUpdateManager statusUpdateManager(flags);

  Try<ResourceEstimator*> resourceEstimator =
    ResourceEstimator::create(flags.resource_estimator);

  if (resourceEstimator.isError()) {
    cerr << "Failed to create resource estimator: "
         << resourceEstimator.error() << endl;
    return EXIT_FAILURE;
  }

  Try<QoSController*> qosController =
    QoSController::create(flags.qos_controller);

  if (qosController.isError()) {
    cerr << "Failed to create QoS Controller: "
         << qosController.error() << endl;
    return EXIT_FAILURE;
  }

  LOG(INFO) << "Starting Mesos agent";

  Slave* slave = new Slave(
      id,
      flags,
      detector,
      containerizer.get(),
      &files,
      &gc,
      &statusUpdateManager,
      resourceEstimator.get(),
      qosController.get());

  process::spawn(slave);
  process::wait(slave->self());

  delete slave;

  delete resourceEstimator.get();

  delete qosController.get();

  delete detector;

  delete containerizer.get();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "Distributions.hh"
#include "conf.hh"
#include "LinearAlgebra.hh"
#include "HmmSet.hh"
#include "str.hh"

std::string stat_file;
conf::Config config;
HmmSet model;

int
main(int argc, char *argv[])
{
  try {
    config("usage: optimize [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('b', "base=BASENAME", "arg", "", "Previous base filename for model files")
      ('g', "gk=FILE", "arg", "", "Previous mixture base distributions")
      ('m', "mc=FILE", "arg", "", "Previous mixture coefficients for the states")
      ('p', "ph=FILE", "arg", "", "Previous HMM definitions")
      ('o', "out=FILE", "arg must", "", "base output file for the coefficients (will be appended with _bindex)")
      ('L', "list=LISTNAME", "arg", "", "file with one statistics file per line")
      ('\0', "subspace=FILE", "arg", "", "use an already initialized subspace")
      ('\0', "to-pcgmm", "", "", "convert Gaussians to have a subspace constraint on precisions")
      ('\0', "to-scgmm", "", "", "convert Gaussians to have an exponential subspace constraint")
      ('\0', "ml", "", "", "maximum likelihood estimation")
      ('\0', "mmi", "", "", "maximum mutual information estimation")
      ('\0', "minvar=FLOAT", "arg", "0.1", "minimum variance (default 0.1)")
      ('\0', "covsmooth", "arg", "0", "covariance smoothing (default 0.0)")
      ('\0', "C1=FLOAT", "arg", "1.0", "constant \"C1\" for MMI updates (default 1.0)")
      ('\0', "C2=FLOAT", "arg", "2.0", "constant \"C2\" for MMI updates (default 2.0)")
      ('\0', "ismooth=FLOAT", "arg", "0.0", "I-smoothing constant for discriminative training (default 0.0)")
      ('\0', "hcl_bfgs_cfg=FILE", "arg", "", "configuration file for HCL biconjugate gradient algorithm")
      ('\0', "hcl_line_cfg=FILE", "arg", "", "configuration file for HCL line search algorithm")
      ('B', "batch=INT", "arg", "0", "number of batch processes with the same recipe")
      ('I', "bindex=INT", "arg", "0", "batch process index")
      ('i', "info=INT", "arg", "0", "info level")
      ;
    config.default_parse(argc, argv);

    // Load the previous models
    if (config["base"].specified)
      model.read_all(config["base"].get_str());
    else {
      if (config["gk"].specified)
        model.read_gk(config["gk"].get_str());
      else
        throw std::string("At least --gk should be defined");
      if (config["mc"].specified)
        model.read_mc(config["mc"].get_str());
      if (config["ph"].specified)
        model.read_ph(config["ph"].get_str());
    }

    // Linesearch for subspace models
    HCL_LineSearch_MT_d ls;
    if (config["hcl_line_cfg"].specified)
      ls.Parameters().Merge(config["hcl_line_cfg"].get_str().c_str());

    // lmBFGS for subspace models
    HCL_UMin_lbfgs_d bfgs(&ls);
    if (config["hcl_bfgs_cfg"].specified)
      bfgs.Parameters().Merge(config["hcl_bfgs_cfg"].get_str().c_str());

    model.set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());

    // Open the file for writing out the subspace coefficients
    std::string outfilename = config["out"].get_str() + "_" + str::fmt(256, "%d", config["bindex"].get_int());
    std::ofstream outfile(outfilename.c_str());
    if (!outfile)
    {
      fprintf(stderr, "Could not open %s for writing\n", config["out"].get_str().c_str());
      exit(1);
    }

    // Optimize coefficients for this batch
    int start_pos = int(floor( (config["bindex"].get_int()-1) * model.num_pool_pdfs() / config["batch"].get_int() ));
    int end_pos = int(ceil( config["bindex"].get_int() * model.num_pool_pdfs() / config["batch"].get_int() ));

    // Print out some information
    if (config["info"].get_int()>0)
      std::cout << "Processing Gaussians " << start_pos+1 << "-" << end_pos
                << " of " << model.num_pool_pdfs() << std::endl;

    // Convert based on the statistics
    if (config["list"].specified) {

      if (!config["base"].specified &&
          !(config["gk"].specified && config["mc"].specified && config["ph"].specified))
        throw std::string("Must give either --base or all --gk, --mc and --ph");

      if (config["mmi"].specified && config["ml"].specified)
        throw std::string("Don't define both --ml and --mmi!");

      if (!config["mmi"].specified && !config["ml"].specified)
        throw std::string("Define either --ml or --mmi!");

      // ML or MMI?
      if (config["ml"].specified)
        model.set_estimation_mode(PDF::ML);
      else
        model.set_estimation_mode(PDF::MMI);

      // Open the list of statistics files
      std::ifstream filelist(config["list"].get_str().c_str());
      if (!filelist)
      {
        fprintf(stderr, "Could not open %s\n", config["list"].get_str().c_str());
        exit(1);
      }

      // Set parameters for Gaussian estimation
      model.set_gaussian_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());

      // Accumulate .gk statistics
      model.start_accumulating();
      while (filelist >> stat_file && stat_file != " ")
        model.accumulate_gk_from_dump(stat_file+".gks");

      for (int g=start_pos; g<end_pos; g++)
      {
        PrecisionConstrainedGaussian *pc = dynamic_cast< PrecisionConstrainedGaussian* > (model.get_pool_pdf(g));
        SubspaceConstrainedGaussian *sc = dynamic_cast< SubspaceConstrainedGaussian* > (model.get_pool_pdf(g));

        if (pc != NULL || sc != NULL)
          std::cout << "Training Gaussian: " << g+1 << "/" << model.num_pool_pdfs() << std::endl;

        try {
          if (pc != NULL)
            pc->estimate_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());
          else if (sc != NULL)
            sc->estimate_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());
        } catch (std::string errstr) {
          std::cout << "Warning: Gaussian number " << g
                    << ": " << errstr << std::endl;
        }

        outfile << g;
        if (pc != NULL) {
          pc->write(outfile);
        }
        else if (sc != NULL) {
          sc->write(outfile);
        }
        outfile << std::endl;
      }
    }

    // Convert the old model
    else {
      if (!config["to-pcgmm"].specified && !config["to-scgmm"].specified)
        throw std::string("Define either --to-pcgmm or --to-scgmm if you want to convert an old model!");
      if (config["to-pcgmm"].specified && config["to-scgmm"].specified)
        throw std::string("Don't define both --to-pcgmm and --to-scgmm if you want to convert an old model!");
      if (!config["subspace"].specified)
        throw std::string("Please specify --subspace if you want to convert an old model");

      PrecisionSubspace *ps;
      ExponentialSubspace *es;

      if (config["to-pcgmm"].specified) {
        ps = new PrecisionSubspace();
        std::ifstream in(config["subspace"].get_str().c_str());
        ps->read_subspace(in);
        ps->set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());
        in.close();
      }
      else if (config["to-scgmm"].specified) {
        es = new ExponentialSubspace();
        std::ifstream in(config["subspace"].get_str().c_str());
        es->read_subspace(in);
        es->set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());
        in.close();
      }

      Matrix covariance;
      Vector mean;
      for (int g=start_pos; g<end_pos; g++) {

        // Print Gaussian index
        if (config["info"].get_int()>0)
          std::cout << "Converting Gaussian: " << g+1 << "/" << model.num_pool_pdfs();

        // Fetch source Gaussian
        Gaussian *source_gaussian = dynamic_cast< Gaussian* > (model.get_pool_pdf(g));
        if (source_gaussian == NULL)
          continue;

        Gaussian *target_gaussian;
        if (config["to-pcgmm"].specified)
          target_gaussian = new PrecisionConstrainedGaussian(ps);
        else if (config["to-scgmm"].specified)
          target_gaussian = new SubspaceConstrainedGaussian(es);

        // Get the old Gaussian parameters
        source_gaussian->get_covariance(covariance);
        source_gaussian->get_mean(mean);

        // Set parameters
        target_gaussian->set_parameters(mean, covariance);

        // Print kullback-leibler
        if (config["info"].get_int() > 0) {
          std::cout << "\tkl-divergence: " << source_gaussian->kullback_leibler(*target_gaussian);
          std::cout << std::endl;
        }

        outfile << g;
        target_gaussian->write(outfile);
        outfile << std::endl;
      }

      outfile.close();
    }
  }

  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }
  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }
}

<commit_msg>name for the output file slightly changed<commit_after>#include "Distributions.hh"
#include "conf.hh"
#include "LinearAlgebra.hh"
#include "HmmSet.hh"
#include "str.hh"

std::string stat_file;
conf::Config config;
HmmSet model;

int
main(int argc, char *argv[])
{
  try {
    config("usage: optimize [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('b', "base=BASENAME", "arg", "", "Previous base filename for model files")
      ('g', "gk=FILE", "arg", "", "Previous mixture base distributions")
      ('m', "mc=FILE", "arg", "", "Previous mixture coefficients for the states")
      ('p', "ph=FILE", "arg", "", "Previous HMM definitions")
      ('o', "out=FILE", "arg must", "", "output file for the coefficients")
      ('L', "list=LISTNAME", "arg", "", "file with one statistics file per line")
      ('\0', "subspace=FILE", "arg", "", "use an already initialized subspace")
      ('\0', "to-pcgmm", "", "", "convert Gaussians to have a subspace constraint on precisions")
      ('\0', "to-scgmm", "", "", "convert Gaussians to have an exponential subspace constraint")
      ('\0', "ml", "", "", "maximum likelihood estimation")
      ('\0', "mmi", "", "", "maximum mutual information estimation")
      ('\0', "minvar=FLOAT", "arg", "0.1", "minimum variance (default 0.1)")
      ('\0', "covsmooth", "arg", "0", "covariance smoothing (default 0.0)")
      ('\0', "C1=FLOAT", "arg", "1.0", "constant \"C1\" for MMI updates (default 1.0)")
      ('\0', "C2=FLOAT", "arg", "2.0", "constant \"C2\" for MMI updates (default 2.0)")
      ('\0', "ismooth=FLOAT", "arg", "0.0", "I-smoothing constant for discriminative training (default 0.0)")
      ('\0', "hcl_bfgs_cfg=FILE", "arg", "", "configuration file for HCL biconjugate gradient algorithm")
      ('\0', "hcl_line_cfg=FILE", "arg", "", "configuration file for HCL line search algorithm")
      ('B', "batch=INT", "arg", "0", "number of batch processes with the same recipe")
      ('I', "bindex=INT", "arg", "0", "batch process index")
      ('i', "info=INT", "arg", "0", "info level")
      ;
    config.default_parse(argc, argv);

    // Load the previous models
    if (config["base"].specified)
      model.read_all(config["base"].get_str());
    else {
      if (config["gk"].specified)
        model.read_gk(config["gk"].get_str());
      else
        throw std::string("At least --gk should be defined");
      if (config["mc"].specified)
        model.read_mc(config["mc"].get_str());
      if (config["ph"].specified)
        model.read_ph(config["ph"].get_str());
    }

    // Linesearch for subspace models
    HCL_LineSearch_MT_d ls;
    if (config["hcl_line_cfg"].specified)
      ls.Parameters().Merge(config["hcl_line_cfg"].get_str().c_str());

    // lmBFGS for subspace models
    HCL_UMin_lbfgs_d bfgs(&ls);
    if (config["hcl_bfgs_cfg"].specified)
      bfgs.Parameters().Merge(config["hcl_bfgs_cfg"].get_str().c_str());

    model.set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());

    // Open the file for writing out the subspace coefficients
    std::string outfilename = config["out"].get_str();
    std::ofstream outfile(outfilename.c_str());
    if (!outfile)
    {
      fprintf(stderr, "Could not open %s for writing\n", config["out"].get_str().c_str());
      exit(1);
    }

    // Optimize coefficients for this batch
    int start_pos = int(floor( (config["bindex"].get_int()-1) * model.num_pool_pdfs() / config["batch"].get_int() ));
    int end_pos = int(ceil( config["bindex"].get_int() * model.num_pool_pdfs() / config["batch"].get_int() ));

    // Print out some information
    if (config["info"].get_int()>0)
      std::cout << "Processing Gaussians " << start_pos+1 << "-" << end_pos
                << " of " << model.num_pool_pdfs() << std::endl;

    // Convert based on the statistics
    if (config["list"].specified) {

      if (!config["base"].specified &&
          !(config["gk"].specified && config["mc"].specified && config["ph"].specified))
        throw std::string("Must give either --base or all --gk, --mc and --ph");

      if (config["mmi"].specified && config["ml"].specified)
        throw std::string("Don't define both --ml and --mmi!");

      if (!config["mmi"].specified && !config["ml"].specified)
        throw std::string("Define either --ml or --mmi!");

      // ML or MMI?
      if (config["ml"].specified)
        model.set_estimation_mode(PDF::ML);
      else
        model.set_estimation_mode(PDF::MMI);

      // Open the list of statistics files
      std::ifstream filelist(config["list"].get_str().c_str());
      if (!filelist)
      {
        fprintf(stderr, "Could not open %s\n", config["list"].get_str().c_str());
        exit(1);
      }

      // Set parameters for Gaussian estimation
      model.set_gaussian_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());

      // Accumulate .gk statistics
      model.start_accumulating();
      while (filelist >> stat_file && stat_file != " ")
        model.accumulate_gk_from_dump(stat_file+".gks");

      for (int g=start_pos; g<end_pos; g++)
      {
        PrecisionConstrainedGaussian *pc = dynamic_cast< PrecisionConstrainedGaussian* > (model.get_pool_pdf(g));
        SubspaceConstrainedGaussian *sc = dynamic_cast< SubspaceConstrainedGaussian* > (model.get_pool_pdf(g));

        if (pc != NULL || sc != NULL)
          std::cout << "Training Gaussian: " << g+1 << "/" << model.num_pool_pdfs() << std::endl;

        try {
          if (pc != NULL)
            pc->estimate_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());
          else if (sc != NULL)
            sc->estimate_parameters(config["minvar"].get_double(),
                                    config["covsmooth"].get_double(),
                                    config["C1"].get_double(),
                                    config["C2"].get_double(),
                                    config["ismooth"].get_double());
        } catch (std::string errstr) {
          std::cout << "Warning: Gaussian number " << g
                    << ": " << errstr << std::endl;
        }

        outfile << g;
        if (pc != NULL) {
          pc->write(outfile);
        }
        else if (sc != NULL) {
          sc->write(outfile);
        }
        outfile << std::endl;
      }
    }

    // Convert the old model
    else {
      if (!config["to-pcgmm"].specified && !config["to-scgmm"].specified)
        throw std::string("Define either --to-pcgmm or --to-scgmm if you want to convert an old model!");
      if (config["to-pcgmm"].specified && config["to-scgmm"].specified)
        throw std::string("Don't define both --to-pcgmm and --to-scgmm if you want to convert an old model!");
      if (!config["subspace"].specified)
        throw std::string("Please specify --subspace if you want to convert an old model");

      PrecisionSubspace *ps;
      ExponentialSubspace *es;

      if (config["to-pcgmm"].specified) {
        ps = new PrecisionSubspace();
        std::ifstream in(config["subspace"].get_str().c_str());
        ps->read_subspace(in);
        ps->set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());
        in.close();
      }
      else if (config["to-scgmm"].specified) {
        es = new ExponentialSubspace();
        std::ifstream in(config["subspace"].get_str().c_str());
        es->read_subspace(in);
        es->set_hcl_optimization(&ls, &bfgs, config["hcl_line_cfg"].get_str(), config["hcl_bfgs_cfg"].get_str());
        in.close();
      }

      Matrix covariance;
      Vector mean;
      for (int g=start_pos; g<end_pos; g++) {

        // Print Gaussian index
        if (config["info"].get_int()>0)
          std::cout << "Converting Gaussian: " << g+1 << "/" << model.num_pool_pdfs();

        // Fetch source Gaussian
        Gaussian *source_gaussian = dynamic_cast< Gaussian* > (model.get_pool_pdf(g));
        if (source_gaussian == NULL)
          continue;

        Gaussian *target_gaussian;
        if (config["to-pcgmm"].specified)
          target_gaussian = new PrecisionConstrainedGaussian(ps);
        else if (config["to-scgmm"].specified)
          target_gaussian = new SubspaceConstrainedGaussian(es);

        // Get the old Gaussian parameters
        source_gaussian->get_covariance(covariance);
        source_gaussian->get_mean(mean);

        // Set parameters
        target_gaussian->set_parameters(mean, covariance);

        // Print kullback-leibler
        if (config["info"].get_int() > 0) {
          std::cout << "\tkl-divergence: " << source_gaussian->kullback_leibler(*target_gaussian);
          std::cout << std::endl;
        }

        outfile << g;
        target_gaussian->write(outfile);
        outfile << std::endl;
      }

      outfile.close();
    }
  }

  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }
  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }
}

<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "accumulators.h"
#include "chain.h"
#include "primitives/deterministicmint.h"
#include "main.h"
#include "stakeinput.h"
#include "wallet.h"

CZPivStake::CZPivStake(const libzerocoin::CoinSpend& spend)
{
    this->nChecksum = spend.getAccumulatorChecksum();
    this->denom = spend.getDenomination();
    uint256 nSerial = spend.getCoinSerialNumber().getuint256();
    this->hashSerial = Hash(nSerial.begin(), nSerial.end());
    this->pindexFrom = nullptr;
    fMint = false;
}

int CZPivStake::GetChecksumHeightFromMint()
{
    int nHeightChecksum = chainActive.Height() - Params().Zerocoin_RequiredStakeDepth();

    //Need to return the first occurance of this checksum in order for the validation process to identify a specific
    //block height
    uint32_t nChecksum = 0;
    nChecksum = ParseChecksum(chainActive[nHeightChecksum]->nAccumulatorCheckpoint, denom);
    return GetChecksumHeight(nChecksum, denom);
}

int CZPivStake::GetChecksumHeightFromSpend()
{
    return GetChecksumHeight(nChecksum, denom);
}

uint32_t CZPivStake::GetChecksum()
{
    return nChecksum;
}

// The zPIV block index is the first appearance of the accumulator checksum that was used in the spend
// note that this also means when staking that this checksum should be from a block that is beyond 60 minutes old and
// 100 blocks deep.
CBlockIndex* CZPivStake::GetIndexFrom()
{
    if (pindexFrom)
        return pindexFrom;

    int nHeightChecksum = 0;

    if (fMint)
        nHeightChecksum = GetChecksumHeightFromMint();
    else
        nHeightChecksum = GetChecksumHeightFromSpend();

    if (nHeightChecksum < Params().Zerocoin_StartHeight() || nHeightChecksum > chainActive.Height()) {
        pindexFrom = nullptr;
    } else {
        //note that this will be a nullptr if the height DNE
        pindexFrom = chainActive[nHeightChecksum];
    }

    return pindexFrom;
}

CAmount CZPivStake::GetValue()
{
    return denom * COIN;
}

//Use the first accumulator checkpoint that occurs 60 minutes after the block being staked from
// In case of regtest, next accumulator of 60 blocks after the block being staked from
bool CZPivStake::GetModifier(uint64_t& nStakeModifier)
{
    CBlockIndex* pindex = GetIndexFrom();
    if (!pindex)
        return error("%s: failed to get index from", __func__);

    if(Params().NetworkID() != CBaseChainParams::REGTEST) {
        // Stake modifier is fixed for now, move it to 60 blocks after this pindex in the future..
        nStakeModifier = pindexFrom->nStakeModifier;
        return true;
    }

    int64_t nTimeBlockFrom = pindex->GetBlockTime();
    while (true) {
        if (pindex->GetBlockTime() - nTimeBlockFrom > 60 * 60) {
            nStakeModifier = pindex->nAccumulatorCheckpoint.Get64();
            return true;
        }

        if (pindex->nHeight + 1 <= chainActive.Height())
            pindex = chainActive.Next(pindex);
        else
            return false;
    }
}

CDataStream CZPivStake::GetUniqueness()
{
    //The unique identifier for a zPIV is a hash of the serial
    CDataStream ss(SER_GETHASH, 0);
    ss << hashSerial;
    return ss;
}

bool CZPivStake::CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut)
{
    CBlockIndex* pindexCheckpoint = GetIndexFrom();
    if (!pindexCheckpoint)
        return error("%s: failed to find checkpoint block index", __func__);

    CZerocoinMint mint;
    if (!pwallet->GetMintFromStakeHash(hashSerial, mint))
        return error("%s: failed to fetch mint associated with serial hash %s", __func__, hashSerial.GetHex());

    if (libzerocoin::ExtractVersionFromSerial(mint.GetSerialNumber()) < 2)
        return error("%s: serial extract is less than v2", __func__);

    int nSecurityLevel = 100;
    CZerocoinSpendReceipt receipt;
    if (!pwallet->MintToTxIn(mint, nSecurityLevel, hashTxOut, txIn, receipt, libzerocoin::SpendType::STAKE, GetIndexFrom()))
        return error("%s\n", receipt.GetStatusMessage());

    return true;
}

bool CZPivStake::CreateTxOuts(CWallet* pwallet, vector<CTxOut>& vout, CAmount nTotal)
{
    //Create an output returning the zPIV that was staked
    CTxOut outReward;
    libzerocoin::CoinDenomination denomStaked = libzerocoin::AmountToZerocoinDenomination(this->GetValue());
    CDeterministicMint dMint;
    if (!pwallet->CreateZPIVOutPut(denomStaked, outReward, dMint))
        return error("%s: failed to create zPIV output", __func__);
    vout.emplace_back(outReward);

    //Add new staked denom to our wallet
    if (!pwallet->DatabaseMint(dMint))
        return error("%s: failed to database the staked zPIV", __func__);

    for (unsigned int i = 0; i < 3; i++) {
        CTxOut out;
        CDeterministicMint dMintReward;
        if (!pwallet->CreateZPIVOutPut(libzerocoin::CoinDenomination::ZQ_ONE, out, dMintReward))
            return error("%s: failed to create zPIV output", __func__);
        vout.emplace_back(out);

        if (!pwallet->DatabaseMint(dMintReward))
            return error("%s: failed to database mint reward", __func__);
    }

    return true;
}

bool CZPivStake::GetTxFrom(CTransaction& tx)
{
    return false;
}

bool CZPivStake::MarkSpent(CWallet *pwallet, const uint256& txid)
{
    CzPIVTracker* zpivTracker = pwallet->zpivTracker.get();
    CMintMeta meta;
    if (!zpivTracker->GetMetaFromStakeHash(hashSerial, meta))
        return error("%s: tracker does not have serialhash", __func__);

    zpivTracker->SetPubcoinUsed(meta.hashPubcoin, txid);
    return true;
}

//!PIV Stake
bool CPivStake::SetInput(CTransaction txPrev, unsigned int n)
{
    this->txFrom = txPrev;
    this->nPosition = n;
    return true;
}

bool CPivStake::GetTxFrom(CTransaction& tx)
{
    tx = txFrom;
    return true;
}

bool CPivStake::CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut)
{
    txIn = CTxIn(txFrom.GetHash(), nPosition);
    return true;
}

CAmount CPivStake::GetValue()
{
    return txFrom.vout[nPosition].nValue;
}

bool CPivStake::CreateTxOuts(CWallet* pwallet, vector<CTxOut>& vout, CAmount nTotal)
{
    vector<valtype> vSolutions;
    txnouttype whichType;
    CScript scriptPubKeyKernel = txFrom.vout[nPosition].scriptPubKey;
    if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) {
        LogPrintf("CreateCoinStake : failed to parse kernel\n");
        return false;
    }

    if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH)
        return false; // only support pay to public key and pay to address

    CScript scriptPubKey;
    if (whichType == TX_PUBKEYHASH) // pay to address type
    {
        //convert to pay to public key type
        CKey key;
        CKeyID keyID = CKeyID(uint160(vSolutions[0]));
        if (!pwallet->GetKey(keyID, key))
            return false;

        scriptPubKey << key.GetPubKey() << OP_CHECKSIG;
    } else
        scriptPubKey = scriptPubKeyKernel;

    vout.emplace_back(CTxOut(0, scriptPubKey));

    // Calculate if we need to split the output
    if (nTotal / 2 > (CAmount)(pwallet->nStakeSplitThreshold * COIN))
        vout.emplace_back(CTxOut(0, scriptPubKey));

    return true;
}

bool CPivStake::GetModifier(uint64_t& nStakeModifier)
{
    int nStakeModifierHeight = 0;
    int64_t nStakeModifierTime = 0;
    GetIndexFrom();
    if (!pindexFrom)
        return error("%s: failed to get index from", __func__);

    if (!GetKernelStakeModifier(pindexFrom->GetBlockHash(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, false))
        return error("CheckStakeKernelHash(): failed to get kernel stake modifier \n");

    return true;
}

CDataStream CPivStake::GetUniqueness()
{
    //The unique identifier for a PIV stake is the outpoint
    CDataStream ss(SER_NETWORK, 0);
    ss << nPosition << txFrom.GetHash();
    return ss;
}

//The block that the UTXO was added to the chain
CBlockIndex* CPivStake::GetIndexFrom()
{
    uint256 hashBlock = 0;
    CTransaction tx;
    if (GetTransaction(txFrom.GetHash(), tx, hashBlock, true)) {
        // If the index is in the chain, then set it as the "index from"
        if (mapBlockIndex.count(hashBlock)) {
            CBlockIndex* pindex = mapBlockIndex.at(hashBlock);
            if (chainActive.Contains(pindex))
                pindexFrom = pindex;
        }
    } else {
        LogPrintf("%s : failed to find tx %s\n", __func__, txFrom.GetHash().GetHex());
    }

    return pindexFrom;
}<commit_msg>REGTEST: Fix bug on GetModifier<commit_after>// Copyright (c) 2017-2018 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "accumulators.h"
#include "chain.h"
#include "primitives/deterministicmint.h"
#include "main.h"
#include "stakeinput.h"
#include "wallet.h"

CZPivStake::CZPivStake(const libzerocoin::CoinSpend& spend)
{
    this->nChecksum = spend.getAccumulatorChecksum();
    this->denom = spend.getDenomination();
    uint256 nSerial = spend.getCoinSerialNumber().getuint256();
    this->hashSerial = Hash(nSerial.begin(), nSerial.end());
    this->pindexFrom = nullptr;
    fMint = false;
}

int CZPivStake::GetChecksumHeightFromMint()
{
    int nHeightChecksum = chainActive.Height() - Params().Zerocoin_RequiredStakeDepth();

    //Need to return the first occurance of this checksum in order for the validation process to identify a specific
    //block height
    uint32_t nChecksum = 0;
    nChecksum = ParseChecksum(chainActive[nHeightChecksum]->nAccumulatorCheckpoint, denom);
    return GetChecksumHeight(nChecksum, denom);
}

int CZPivStake::GetChecksumHeightFromSpend()
{
    return GetChecksumHeight(nChecksum, denom);
}

uint32_t CZPivStake::GetChecksum()
{
    return nChecksum;
}

// The zPIV block index is the first appearance of the accumulator checksum that was used in the spend
// note that this also means when staking that this checksum should be from a block that is beyond 60 minutes old and
// 100 blocks deep.
CBlockIndex* CZPivStake::GetIndexFrom()
{
    if (pindexFrom)
        return pindexFrom;

    int nHeightChecksum = 0;

    if (fMint)
        nHeightChecksum = GetChecksumHeightFromMint();
    else
        nHeightChecksum = GetChecksumHeightFromSpend();

    if (nHeightChecksum < Params().Zerocoin_StartHeight() || nHeightChecksum > chainActive.Height()) {
        pindexFrom = nullptr;
    } else {
        //note that this will be a nullptr if the height DNE
        pindexFrom = chainActive[nHeightChecksum];
    }

    return pindexFrom;
}

CAmount CZPivStake::GetValue()
{
    return denom * COIN;
}

//Use the first accumulator checkpoint that occurs 60 minutes after the block being staked from
// In case of regtest, next accumulator of 60 blocks after the block being staked from
bool CZPivStake::GetModifier(uint64_t& nStakeModifier)
{
    CBlockIndex* pindex = GetIndexFrom();
    if (!pindex)
        return error("%s: failed to get index from", __func__);

    if(Params().NetworkID() == CBaseChainParams::REGTEST) {
        // Stake modifier is fixed for now, move it to 60 blocks after this pindex in the future..
        nStakeModifier = pindexFrom->nStakeModifier;
        return true;
    }

    int64_t nTimeBlockFrom = pindex->GetBlockTime();
    while (true) {
        if (pindex->GetBlockTime() - nTimeBlockFrom > 60 * 60) {
            nStakeModifier = pindex->nAccumulatorCheckpoint.Get64();
            return true;
        }

        if (pindex->nHeight + 1 <= chainActive.Height())
            pindex = chainActive.Next(pindex);
        else
            return false;
    }
}

CDataStream CZPivStake::GetUniqueness()
{
    //The unique identifier for a zPIV is a hash of the serial
    CDataStream ss(SER_GETHASH, 0);
    ss << hashSerial;
    return ss;
}

bool CZPivStake::CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut)
{
    CBlockIndex* pindexCheckpoint = GetIndexFrom();
    if (!pindexCheckpoint)
        return error("%s: failed to find checkpoint block index", __func__);

    CZerocoinMint mint;
    if (!pwallet->GetMintFromStakeHash(hashSerial, mint))
        return error("%s: failed to fetch mint associated with serial hash %s", __func__, hashSerial.GetHex());

    if (libzerocoin::ExtractVersionFromSerial(mint.GetSerialNumber()) < 2)
        return error("%s: serial extract is less than v2", __func__);

    int nSecurityLevel = 100;
    CZerocoinSpendReceipt receipt;
    if (!pwallet->MintToTxIn(mint, nSecurityLevel, hashTxOut, txIn, receipt, libzerocoin::SpendType::STAKE, GetIndexFrom()))
        return error("%s\n", receipt.GetStatusMessage());

    return true;
}

bool CZPivStake::CreateTxOuts(CWallet* pwallet, vector<CTxOut>& vout, CAmount nTotal)
{
    //Create an output returning the zPIV that was staked
    CTxOut outReward;
    libzerocoin::CoinDenomination denomStaked = libzerocoin::AmountToZerocoinDenomination(this->GetValue());
    CDeterministicMint dMint;
    if (!pwallet->CreateZPIVOutPut(denomStaked, outReward, dMint))
        return error("%s: failed to create zPIV output", __func__);
    vout.emplace_back(outReward);

    //Add new staked denom to our wallet
    if (!pwallet->DatabaseMint(dMint))
        return error("%s: failed to database the staked zPIV", __func__);

    for (unsigned int i = 0; i < 3; i++) {
        CTxOut out;
        CDeterministicMint dMintReward;
        if (!pwallet->CreateZPIVOutPut(libzerocoin::CoinDenomination::ZQ_ONE, out, dMintReward))
            return error("%s: failed to create zPIV output", __func__);
        vout.emplace_back(out);

        if (!pwallet->DatabaseMint(dMintReward))
            return error("%s: failed to database mint reward", __func__);
    }

    return true;
}

bool CZPivStake::GetTxFrom(CTransaction& tx)
{
    return false;
}

bool CZPivStake::MarkSpent(CWallet *pwallet, const uint256& txid)
{
    CzPIVTracker* zpivTracker = pwallet->zpivTracker.get();
    CMintMeta meta;
    if (!zpivTracker->GetMetaFromStakeHash(hashSerial, meta))
        return error("%s: tracker does not have serialhash", __func__);

    zpivTracker->SetPubcoinUsed(meta.hashPubcoin, txid);
    return true;
}

//!PIV Stake
bool CPivStake::SetInput(CTransaction txPrev, unsigned int n)
{
    this->txFrom = txPrev;
    this->nPosition = n;
    return true;
}

bool CPivStake::GetTxFrom(CTransaction& tx)
{
    tx = txFrom;
    return true;
}

bool CPivStake::CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut)
{
    txIn = CTxIn(txFrom.GetHash(), nPosition);
    return true;
}

CAmount CPivStake::GetValue()
{
    return txFrom.vout[nPosition].nValue;
}

bool CPivStake::CreateTxOuts(CWallet* pwallet, vector<CTxOut>& vout, CAmount nTotal)
{
    vector<valtype> vSolutions;
    txnouttype whichType;
    CScript scriptPubKeyKernel = txFrom.vout[nPosition].scriptPubKey;
    if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) {
        LogPrintf("CreateCoinStake : failed to parse kernel\n");
        return false;
    }

    if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH)
        return false; // only support pay to public key and pay to address

    CScript scriptPubKey;
    if (whichType == TX_PUBKEYHASH) // pay to address type
    {
        //convert to pay to public key type
        CKey key;
        CKeyID keyID = CKeyID(uint160(vSolutions[0]));
        if (!pwallet->GetKey(keyID, key))
            return false;

        scriptPubKey << key.GetPubKey() << OP_CHECKSIG;
    } else
        scriptPubKey = scriptPubKeyKernel;

    vout.emplace_back(CTxOut(0, scriptPubKey));

    // Calculate if we need to split the output
    if (nTotal / 2 > (CAmount)(pwallet->nStakeSplitThreshold * COIN))
        vout.emplace_back(CTxOut(0, scriptPubKey));

    return true;
}

bool CPivStake::GetModifier(uint64_t& nStakeModifier)
{
    int nStakeModifierHeight = 0;
    int64_t nStakeModifierTime = 0;
    GetIndexFrom();
    if (!pindexFrom)
        return error("%s: failed to get index from", __func__);

    if (!GetKernelStakeModifier(pindexFrom->GetBlockHash(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, false))
        return error("CheckStakeKernelHash(): failed to get kernel stake modifier \n");

    return true;
}

CDataStream CPivStake::GetUniqueness()
{
    //The unique identifier for a PIV stake is the outpoint
    CDataStream ss(SER_NETWORK, 0);
    ss << nPosition << txFrom.GetHash();
    return ss;
}

//The block that the UTXO was added to the chain
CBlockIndex* CPivStake::GetIndexFrom()
{
    uint256 hashBlock = 0;
    CTransaction tx;
    if (GetTransaction(txFrom.GetHash(), tx, hashBlock, true)) {
        // If the index is in the chain, then set it as the "index from"
        if (mapBlockIndex.count(hashBlock)) {
            CBlockIndex* pindex = mapBlockIndex.at(hashBlock);
            if (chainActive.Contains(pindex))
                pindexFrom = pindex;
        }
    } else {
        LogPrintf("%s : failed to find tx %s\n", __func__, txFrom.GetHash().GetHex());
    }

    return pindexFrom;
}
<|endoftext|>