<commit_before>/* Copyright (c) 2010-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QString>
#include <QByteArray>
#include <QDateTime>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QSqlError>
#include <TWebApplication>
#include <TLogger>
#include <TLog>
#include <TAccessLog>
#include "tsystemglobal.h"
#include "taccesslogstream.h"
#include "tfileaiowriter.h"

static TAccessLogStream *accesslogstrm = 0;
static TAccessLogStream *sqllogstrm = 0;
static TFileAioWriter systemLog;
static QByteArray syslogLayout;
static QByteArray syslogDateTimeFormat;
static QByteArray accessLogLayout;
static QByteArray accessLogDateTimeFormat;

void writeAccessLog(const TAccessLog &log)
{
    if (accesslogstrm) {
        accesslogstrm->writeLog(log.toByteArray(accessLogLayout, accessLogDateTimeFormat));
    }
}

void tSetupSystemLogger()
{
    // Log directory
    QDir logdir(Tf::app()->logPath());
    if (!logdir.exists()) {
        logdir.mkpath(".");
    }

    // system log
    systemLog.setFileName(Tf::app()->systemLogFilePath());
    systemLog.open();

    syslogLayout = Tf::app()->appSettings().value("SystemLog.Layout", "%d %5P %m%n").toByteArray();
    syslogDateTimeFormat = Tf::app()->appSettings().value("SystemLog.DateTimeFormat", "yyyy-MM-ddThh:mm:ss").toByteArray();
}

void tSetupAccessLogger()
{
    // access log
    QString accesslogpath = Tf::app()->accessLogFilePath();
    if (!accesslogstrm && !accesslogpath.isEmpty()) {
        accesslogstrm = new TAccessLogStream(accesslogpath);
    }

    accessLogLayout = Tf::app()->appSettings().value("AccessLog.Layout", "%h %d \"%r\" %s %O%n").toByteArray();
    accessLogDateTimeFormat = Tf::app()->appSettings().value("AccessLog.DateTimeFormat", "yyyy-MM-ddThh:mm:ss").toByteArray();
}

void tSetupQueryLogger()
{
    // sql query log
    QString querylogpath = Tf::app()->sqlQueryLogFilePath();
    if (!sqllogstrm && !querylogpath.isEmpty()) {
        sqllogstrm = new TAccessLogStream(querylogpath);
    }
}

static void tSystemMessage(int priority, const char *msg, va_list ap)
{
    TLog log(priority, QString().vsprintf(msg, ap).toLocal8Bit());
    QByteArray buf = TLogger::logToByteArray(log, syslogLayout, syslogDateTimeFormat);
    systemLog.write(buf.data(), buf.length());
}

void tSystemError(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Error, msg, ap);
    va_end(ap);
}

void tSystemWarn(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Warn, msg, ap);
    va_end(ap);
}

void tSystemInfo(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Info, msg, ap);
    va_end(ap);
}

#ifndef TF_NO_DEBUG

void tSystemDebug(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Debug, msg, ap);
    va_end(ap);
}

void tSystemTrace(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Trace, msg, ap);
    va_end(ap);
}

#else

void tSystemDebug(const char *, ...) { }
void tSystemTrace(const char *, ...) { }

#endif

void tQueryLog(const char *msg, ...)
{
    if (sqllogstrm) {
        va_list ap;
        va_start(ap, msg);
        TLog log(-1, QString().vsprintf(msg, ap).toLocal8Bit());
        QByteArray buf = TLogger::logToByteArray(log, syslogLayout, syslogDateTimeFormat);
        sqllogstrm->writeLog(buf);
        va_end(ap);
    }
}

void tWriteQueryLog(const QString &query, bool success, const QSqlError &error)
{
    QString q = query;

    if (!success) {
        QString err = (!error.databaseText().isEmpty()) ? error.databaseText() : error.text().trimmed();
        if (!err.isEmpty()) {
            err = QLatin1Char('[') + err + QLatin1String("] ");
        }
        q = QLatin1String("(Query failed) ") + err + query;
    }
    tQueryLog("%s", qPrintable(q));
}
<commit_msg>add flushing to access logging.<commit_after>/* Copyright (c) 2010-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QString>
#include <QByteArray>
#include <QDateTime>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QSqlError>
#include <TWebApplication>
#include <TLogger>
#include <TLog>
#include <TAccessLog>
#include "tsystemglobal.h"
#include "taccesslogstream.h"
#include "tfileaiowriter.h"

static TAccessLogStream *accesslogstrm = 0;
static TAccessLogStream *sqllogstrm = 0;
static TFileAioWriter systemLog;
static QByteArray syslogLayout;
static QByteArray syslogDateTimeFormat;
static QByteArray accessLogLayout;
static QByteArray accessLogDateTimeFormat;

void writeAccessLog(const TAccessLog &log)
{
    if (accesslogstrm) {
        accesslogstrm->writeLog(log.toByteArray(accessLogLayout, accessLogDateTimeFormat));

        if (Tf::app()->multiProcessingModule() == TWebApplication::Prefork) {
            accesslogstrm->flush();
        }
    }
}

void tSetupSystemLogger()
{
    // Log directory
    QDir logdir(Tf::app()->logPath());
    if (!logdir.exists()) {
        logdir.mkpath(".");
    }

    // system log
    systemLog.setFileName(Tf::app()->systemLogFilePath());
    systemLog.open();

    syslogLayout = Tf::app()->appSettings().value("SystemLog.Layout", "%d %5P %m%n").toByteArray();
    syslogDateTimeFormat = Tf::app()->appSettings().value("SystemLog.DateTimeFormat", "yyyy-MM-ddThh:mm:ss").toByteArray();
}

void tSetupAccessLogger()
{
    // access log
    QString accesslogpath = Tf::app()->accessLogFilePath();
    if (!accesslogstrm && !accesslogpath.isEmpty()) {
        accesslogstrm = new TAccessLogStream(accesslogpath);
    }

    accessLogLayout = Tf::app()->appSettings().value("AccessLog.Layout", "%h %d \"%r\" %s %O%n").toByteArray();
    accessLogDateTimeFormat = Tf::app()->appSettings().value("AccessLog.DateTimeFormat", "yyyy-MM-ddThh:mm:ss").toByteArray();
}

void tSetupQueryLogger()
{
    // sql query log
    QString querylogpath = Tf::app()->sqlQueryLogFilePath();
    if (!sqllogstrm && !querylogpath.isEmpty()) {
        sqllogstrm = new TAccessLogStream(querylogpath);
    }
}

static void tSystemMessage(int priority, const char *msg, va_list ap)
{
    TLog log(priority, QString().vsprintf(msg, ap).toLocal8Bit());
    QByteArray buf = TLogger::logToByteArray(log, syslogLayout, syslogDateTimeFormat);
    systemLog.write(buf.data(), buf.length());

    if (Tf::app()->multiProcessingModule() == TWebApplication::Prefork) {
        systemLog.flush();
    }
}

void tSystemError(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Error, msg, ap);
    va_end(ap);
}

void tSystemWarn(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Warn, msg, ap);
    va_end(ap);
}

void tSystemInfo(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Info, msg, ap);
    va_end(ap);
}

#ifndef TF_NO_DEBUG

void tSystemDebug(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Debug, msg, ap);
    va_end(ap);
}

void tSystemTrace(const char *msg, ...)
{
    va_list ap;
    va_start(ap, msg);
    tSystemMessage(TLogger::Trace, msg, ap);
    va_end(ap);
}

#else

void tSystemDebug(const char *, ...) { }
void tSystemTrace(const char *, ...) { }

#endif

void tQueryLog(const char *msg, ...)
{
    if (sqllogstrm) {
        va_list ap;
        va_start(ap, msg);
        TLog log(-1, QString().vsprintf(msg, ap).toLocal8Bit());
        QByteArray buf = TLogger::logToByteArray(log, syslogLayout, syslogDateTimeFormat);
        sqllogstrm->writeLog(buf);
        va_end(ap);

        if (Tf::app()->multiProcessingModule() == TWebApplication::Prefork) {
            sqllogstrm->flush();
        }
    }
}

void tWriteQueryLog(const QString &query, bool success, const QSqlError &error)
{
    QString q = query;

    if (!success) {
        QString err = (!error.databaseText().isEmpty()) ? error.databaseText() : error.text().trimmed();
        if (!err.isEmpty()) {
            err = QLatin1Char('[') + err + QLatin1String("] ");
        }
        q = QLatin1String("(Query failed) ") + err + query;
    }
    tQueryLog("%s", qPrintable(q));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */
#pragma once
#include <graphene/protocol/operations.hpp>

namespace graphene { namespace protocol {
   struct predicate_result;

   using rejected_predicate = static_variant<predicate_result, fc::exception>;
   using rejected_predicate_map = map<custom_authority_id_type, rejected_predicate>;
   using custom_authority_lookup = std::function<vector<authority>(account_id_type, const operation&,
                                                                   rejected_predicate_map*)>;

   /**
    * @defgroup transactions Transactions
    *
    * All transactions are sets of operations that must be applied atomically. Transactions must refer to a recent
    * block that defines the context of the operation so that they assert a known binding to the object id's referenced
    * in the transaction.
    *
    * Rather than specify a full block number, we only specify the lower 16 bits of the block number which means you
    * can reference any block within the last 65,536 blocks which is 3.5 days with a 5 second block interval or 18
    * hours with a 1 second interval.
    *
    * All transactions must expire so that the network does not have to maintain a permanent record of all transactions
    * ever published.  A transaction may not have an expiration date too far in the future because this would require
    * keeping too much transaction history in memory.
    *
    * The block prefix is the first 4 bytes of the block hash of the reference block number, which is the second 4
    * bytes of the @ref block_id_type (the first 4 bytes of the block ID are the block number)
    *
    * Note: A transaction which selects a reference block cannot be migrated between forks outside the period of
    * ref_block_num.time to (ref_block_num.time + rel_exp * interval). This fact can be used to protect market orders
    * which should specify a relatively short re-org window of perhaps less than 1 minute. Normal payments should
    * probably have a longer re-org window to ensure their transaction can still go through in the event of a momentary
    * disruption in service.
    *
    * @note It is not recommended to set the @ref ref_block_num, @ref ref_block_prefix, and @ref expiration
    * fields manually. Call the appropriate overload of @ref set_expiration instead.
    *
    * @{
    */

   /**
    *  @brief groups operations that should be applied atomically
    */
   class transaction
   {
   public:
      virtual ~transaction() = default;
      /**
       * Least significant 16 bits from the reference block number. If @ref relative_expiration is zero, this field
       * must be zero as well.
       */
      uint16_t           ref_block_num    = 0;
      /**
       * The first non-block-number 32-bits of the reference block ID. Recall that block IDs have 32 bits of block
       * number followed by the actual block hash, so this field should be set using the second 32 bits in the
       * @ref block_id_type
       */
      uint32_t           ref_block_prefix = 0;

      /**
       * This field specifies the absolute expiration for this transaction.
       */
      fc::time_point_sec expiration;

      vector<operation>  operations;
      extensions_type    extensions;

      /// Calculate the digest for a transaction
      digest_type                        digest()const;
      virtual const transaction_id_type& id()const;
      virtual void                       validate() const;

      void set_expiration( fc::time_point_sec expiration_time );
      void set_reference_block( const block_id_type& reference_block );

      /// visit all operations
      template<typename Visitor>
      vector<typename Visitor::result_type> visit( Visitor&& visitor )
      {
         vector<typename Visitor::result_type> results;
         for( auto& op : operations )
            results.push_back(op.visit( std::forward<Visitor>( visitor ) ));
         return results;
      }
      template<typename Visitor>
      vector<typename Visitor::result_type> visit( Visitor&& visitor )const
      {
         vector<typename Visitor::result_type> results;
         for( auto& op : operations )
            results.push_back(op.visit( std::forward<Visitor>( visitor ) ));
         return results;
      }

      void get_required_authorities( flat_set<account_id_type>& active,
                                     flat_set<account_id_type>& owner,
                                     vector<authority>& other,
                                     bool ignore_custom_operation_required_auths )const;

      virtual uint64_t get_packed_size()const;

   protected:
      // Calculate the digest used for signature validation
      digest_type sig_digest( const chain_id_type& chain_id )const;
      mutable transaction_id_type _tx_id_buffer;
   };

   /**
    *  @brief adds a signature to a transaction
    */
   class signed_transaction : public transaction
   {
   public:
      signed_transaction( const transaction& trx = transaction() )
         : transaction(trx){}
      virtual ~signed_transaction() = default;

      /** signs and appends to signatures */
      const signature_type& sign( const private_key_type& key, const chain_id_type& chain_id );

      /** returns signature but does not append */
      signature_type sign( const private_key_type& key, const chain_id_type& chain_id )const;

      /**
       *  The purpose of this method is to identify some subset of
       *  @ref available_keys that will produce sufficient signatures
       *  for a transaction.  The result is not always a minimal set of
       *  signatures, but any non-minimal result will still pass
       *  validation.
       */
      set<public_key_type> get_required_signatures(
              const chain_id_type& chain_id,
              const flat_set<public_key_type>& available_keys,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_authorities,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;

      /**
       * Checks whether signatures in this signed transaction are sufficient to authorize the transaction.
       *   Throws an exception when failed.
       *
       * @param chain_id the ID of a block chain
       * @param get_active callback function to retrieve active authorities of a given account
       * @param get_owner  callback function to retrieve owner authorities of a given account
       * @param get_custom callback function to retrieve viable custom authorities for a given account and operation
       * @param allow_non_immediate_owner whether to allow owner authority of non-immediately
       *            required accounts to authorize operations in the transaction
       * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the
       *            required_auths field of custom_operation or not
       * @param max_recursion maximum level of recursion when verifying, since an account
       *            can have another account in active authorities and/or owner authorities
       */
      void verify_authority(
              const chain_id_type& chain_id,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              const custom_authority_lookup& get_custom,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_auths,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;

      /**
       * This is a slower replacement for get_required_signatures()
       * which returns a minimal set in all cases, including
       * some cases where get_required_signatures() returns a
       * non-minimal set.
       */
      set<public_key_type> minimize_required_signatures(
              const chain_id_type& chain_id,
              const flat_set<public_key_type>& available_keys,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              const custom_authority_lookup& get_custom,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_auths,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH) const;

      /**
       * @brief Extract public keys from signatures with given chain ID.
       * @param chain_id A chain ID
       * @return Public keys
       * @note If @ref signees is empty, E.G. when it's the first time calling
       *       this function for the signed transaction, public keys will be
       *       extracted with given chain ID, and be stored into the mutable
       *       @ref signees field, then @ref signees will be returned;
       *       otherwise, the @ref chain_id parameter will be ignored, and
       *       @ref signees will be returned directly.
       */
      virtual const flat_set<public_key_type>& get_signature_keys( const chain_id_type& chain_id )const;

      /** Signatures */
      vector<signature_type> signatures;

      /** Removes all operations and signatures */
      void clear() { operations.clear(); signatures.clear(); }

      /** Removes all signatures */
      void clear_signatures() { signatures.clear(); }
   protected:
      /** Public keys extracted from signatures */
      mutable flat_set<public_key_type> _signees;
   };

   /** This represents a signed transaction that will never have its operations,
    *  signatures etc. modified again, after initial creation. It is therefore
    *  safe to cache results from various calls.
    */
   class precomputable_transaction : public signed_transaction {
   public:
      precomputable_transaction() {}
      precomputable_transaction( const signed_transaction& tx ) : signed_transaction(tx) {};
      precomputable_transaction( signed_transaction&& tx ) : signed_transaction( std::move(tx) ) {};
      virtual ~precomputable_transaction() = default;

      virtual const transaction_id_type&       id()const override;
      virtual void                             validate()const override;
      virtual const flat_set<public_key_type>& get_signature_keys( const chain_id_type& chain_id )const override;
      virtual uint64_t                         get_packed_size()const override;
   protected:
      mutable bool _validated = false;
      mutable uint64_t _packed_size = 0;
   };

   /**
    * Checks whether given public keys and approvals are sufficient to authorize given operations.
    *   Throws an exception when failed.
    *
    * @param ops a vector of operations
    * @param sigs a set of public keys
    * @param get_active callback function to retrieve active authorities of a given account
    * @param get_owner  callback function to retrieve owner authorities of a given account
    * @param allow_non_immediate_owner whether to allow owner authority of non-immediately
    *            required accounts to authorize operations
    * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the
    *            required_auths field of custom_operation or not
    * @param max_recursion maximum level of recursion when verifying, since an account
    *            can have another account in active authorities and/or owner authorities
    * @param allow_committee whether to allow the special "committee account" to authorize the operations
    * @param active_approvals accounts that approved the operations with their active authories
    * @param owner_approvals accounts that approved the operations with their owner authories
    */
   void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
                          const std::function<const authority*(account_id_type)>& get_active,
                          const std::function<const authority*(account_id_type)>& get_owner,
                          const custom_authority_lookup& get_custom,
                          bool allow_non_immediate_owner,
                          bool ignore_custom_operation_required_auths,
                          uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH,
                          bool allow_committee = false,
                          const flat_set<account_id_type>& active_aprovals = flat_set<account_id_type>(),
                          const flat_set<account_id_type>& owner_approvals = flat_set<account_id_type>() );

   /**
    *  @brief captures the result of evaluating the operations contained in the transaction
    *
    *  When processing a transaction some operations generate
    *  new object IDs and these IDs cannot be known until the
    *  transaction is actually included into a block.  When a
    *  block is produced these new ids are captured and included
    *  with every transaction.  The index in operation_results should
    *  correspond to the same index in operations.
    *
    *  If an operation did not create any new object IDs then 0
    *  should be returned.
    */
   struct processed_transaction : public precomputable_transaction
   {
      processed_transaction( const signed_transaction& trx = signed_transaction() )
         : precomputable_transaction(trx){}
      virtual ~processed_transaction() = default;

      vector<operation_result> operation_results;

      digest_type merkle_digest()const;
   };

   /// @} transactions group

} } // graphene::protocol

FC_REFLECT( graphene::protocol::transaction, (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions) )
// Note: not reflecting signees field for backward compatibility; in addition, it should not be in p2p messages
FC_REFLECT_DERIVED( graphene::protocol::signed_transaction, (graphene::protocol::transaction), (signatures) )
FC_REFLECT_DERIVED( graphene::protocol::precomputable_transaction, (graphene::protocol::signed_transaction), )
FC_REFLECT_DERIVED( graphene::protocol::processed_transaction, (graphene::protocol::precomputable_transaction), (operation_results) )

GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::signed_transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::precomputable_transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::processed_transaction)
<commit_msg>Add docs for get_custom arg in verify_authority()<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */
#pragma once
#include <graphene/protocol/operations.hpp>

namespace graphene { namespace protocol {
   struct predicate_result;

   using rejected_predicate = static_variant<predicate_result, fc::exception>;
   using rejected_predicate_map = map<custom_authority_id_type, rejected_predicate>;
   using custom_authority_lookup = std::function<vector<authority>(account_id_type, const operation&,
                                                                   rejected_predicate_map*)>;

   /**
    * @defgroup transactions Transactions
    *
    * All transactions are sets of operations that must be applied atomically. Transactions must refer to a recent
    * block that defines the context of the operation so that they assert a known binding to the object id's referenced
    * in the transaction.
    *
    * Rather than specify a full block number, we only specify the lower 16 bits of the block number which means you
    * can reference any block within the last 65,536 blocks which is 3.5 days with a 5 second block interval or 18
    * hours with a 1 second interval.
    *
    * All transactions must expire so that the network does not have to maintain a permanent record of all transactions
    * ever published.  A transaction may not have an expiration date too far in the future because this would require
    * keeping too much transaction history in memory.
    *
    * The block prefix is the first 4 bytes of the block hash of the reference block number, which is the second 4
    * bytes of the @ref block_id_type (the first 4 bytes of the block ID are the block number)
    *
    * Note: A transaction which selects a reference block cannot be migrated between forks outside the period of
    * ref_block_num.time to (ref_block_num.time + rel_exp * interval). This fact can be used to protect market orders
    * which should specify a relatively short re-org window of perhaps less than 1 minute. Normal payments should
    * probably have a longer re-org window to ensure their transaction can still go through in the event of a momentary
    * disruption in service.
    *
    * @note It is not recommended to set the @ref ref_block_num, @ref ref_block_prefix, and @ref expiration
    * fields manually. Call the appropriate overload of @ref set_expiration instead.
    *
    * @{
    */

   /**
    *  @brief groups operations that should be applied atomically
    */
   class transaction
   {
   public:
      virtual ~transaction() = default;
      /**
       * Least significant 16 bits from the reference block number. If @ref relative_expiration is zero, this field
       * must be zero as well.
       */
      uint16_t           ref_block_num    = 0;
      /**
       * The first non-block-number 32-bits of the reference block ID. Recall that block IDs have 32 bits of block
       * number followed by the actual block hash, so this field should be set using the second 32 bits in the
       * @ref block_id_type
       */
      uint32_t           ref_block_prefix = 0;

      /**
       * This field specifies the absolute expiration for this transaction.
       */
      fc::time_point_sec expiration;

      vector<operation>  operations;
      extensions_type    extensions;

      /// Calculate the digest for a transaction
      digest_type                        digest()const;
      virtual const transaction_id_type& id()const;
      virtual void                       validate() const;

      void set_expiration( fc::time_point_sec expiration_time );
      void set_reference_block( const block_id_type& reference_block );

      /// visit all operations
      template<typename Visitor>
      vector<typename Visitor::result_type> visit( Visitor&& visitor )
      {
         vector<typename Visitor::result_type> results;
         for( auto& op : operations )
            results.push_back(op.visit( std::forward<Visitor>( visitor ) ));
         return results;
      }
      template<typename Visitor>
      vector<typename Visitor::result_type> visit( Visitor&& visitor )const
      {
         vector<typename Visitor::result_type> results;
         for( auto& op : operations )
            results.push_back(op.visit( std::forward<Visitor>( visitor ) ));
         return results;
      }

      void get_required_authorities( flat_set<account_id_type>& active,
                                     flat_set<account_id_type>& owner,
                                     vector<authority>& other,
                                     bool ignore_custom_operation_required_auths )const;

      virtual uint64_t get_packed_size()const;

   protected:
      // Calculate the digest used for signature validation
      digest_type sig_digest( const chain_id_type& chain_id )const;
      mutable transaction_id_type _tx_id_buffer;
   };

   /**
    *  @brief adds a signature to a transaction
    */
   class signed_transaction : public transaction
   {
   public:
      signed_transaction( const transaction& trx = transaction() )
         : transaction(trx){}
      virtual ~signed_transaction() = default;

      /** signs and appends to signatures */
      const signature_type& sign( const private_key_type& key, const chain_id_type& chain_id );

      /** returns signature but does not append */
      signature_type sign( const private_key_type& key, const chain_id_type& chain_id )const;

      /**
       *  The purpose of this method is to identify some subset of
       *  @ref available_keys that will produce sufficient signatures
       *  for a transaction.  The result is not always a minimal set of
       *  signatures, but any non-minimal result will still pass
       *  validation.
       */
      set<public_key_type> get_required_signatures(
              const chain_id_type& chain_id,
              const flat_set<public_key_type>& available_keys,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_authorities,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;

      /**
       * Checks whether signatures in this signed transaction are sufficient to authorize the transaction.
       *   Throws an exception when failed.
       *
       * @param chain_id the ID of a block chain
       * @param get_active callback function to retrieve active authorities of a given account
       * @param get_owner  callback function to retrieve owner authorities of a given account
       * @param get_custom callback function to retrieve viable custom authorities for a given account and operation
       * @param allow_non_immediate_owner whether to allow owner authority of non-immediately
       *            required accounts to authorize operations in the transaction
       * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the
       *            required_auths field of custom_operation or not
       * @param max_recursion maximum level of recursion when verifying, since an account
       *            can have another account in active authorities and/or owner authorities
       */
      void verify_authority(
              const chain_id_type& chain_id,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              const custom_authority_lookup& get_custom,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_auths,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;

      /**
       * This is a slower replacement for get_required_signatures()
       * which returns a minimal set in all cases, including
       * some cases where get_required_signatures() returns a
       * non-minimal set.
       */
      set<public_key_type> minimize_required_signatures(
              const chain_id_type& chain_id,
              const flat_set<public_key_type>& available_keys,
              const std::function<const authority*(account_id_type)>& get_active,
              const std::function<const authority*(account_id_type)>& get_owner,
              const custom_authority_lookup& get_custom,
              bool allow_non_immediate_owner,
              bool ignore_custom_operation_required_auths,
              uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH) const;

      /**
       * @brief Extract public keys from signatures with given chain ID.
       * @param chain_id A chain ID
       * @return Public keys
       * @note If @ref signees is empty, E.G. when it's the first time calling
       *       this function for the signed transaction, public keys will be
       *       extracted with given chain ID, and be stored into the mutable
       *       @ref signees field, then @ref signees will be returned;
       *       otherwise, the @ref chain_id parameter will be ignored, and
       *       @ref signees will be returned directly.
       */
      virtual const flat_set<public_key_type>& get_signature_keys( const chain_id_type& chain_id )const;

      /** Signatures */
      vector<signature_type> signatures;

      /** Removes all operations and signatures */
      void clear() { operations.clear(); signatures.clear(); }

      /** Removes all signatures */
      void clear_signatures() { signatures.clear(); }
   protected:
      /** Public keys extracted from signatures */
      mutable flat_set<public_key_type> _signees;
   };

   /** This represents a signed transaction that will never have its operations,
    *  signatures etc. modified again, after initial creation. It is therefore
    *  safe to cache results from various calls.
    */
   class precomputable_transaction : public signed_transaction {
   public:
      precomputable_transaction() {}
      precomputable_transaction( const signed_transaction& tx ) : signed_transaction(tx) {};
      precomputable_transaction( signed_transaction&& tx ) : signed_transaction( std::move(tx) ) {};
      virtual ~precomputable_transaction() = default;

      virtual const transaction_id_type&       id()const override;
      virtual void                             validate()const override;
      virtual const flat_set<public_key_type>& get_signature_keys( const chain_id_type& chain_id )const override;
      virtual uint64_t                         get_packed_size()const override;
   protected:
      mutable bool _validated = false;
      mutable uint64_t _packed_size = 0;
   };

   /**
    * Checks whether given public keys and approvals are sufficient to authorize given operations.
    *   Throws an exception when failed.
    *
    * @param ops a vector of operations
    * @param sigs a set of public keys
    * @param get_active callback function to retrieve active authorities of a given account
    * @param get_owner  callback function to retrieve owner authorities of a given account
    * @param get_custom callback function to retrieve viable custom authorities for a given account and operation
    * @param allow_non_immediate_owner whether to allow owner authority of non-immediately
    *            required accounts to authorize operations
    * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the
    *            required_auths field of custom_operation or not
    * @param max_recursion maximum level of recursion when verifying, since an account
    *            can have another account in active authorities and/or owner authorities
    * @param allow_committee whether to allow the special "committee account" to authorize the operations
    * @param active_approvals accounts that approved the operations with their active authories
    * @param owner_approvals accounts that approved the operations with their owner authories
    */
   void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
                          const std::function<const authority*(account_id_type)>& get_active,
                          const std::function<const authority*(account_id_type)>& get_owner,
                          const custom_authority_lookup& get_custom,
                          bool allow_non_immediate_owner,
                          bool ignore_custom_operation_required_auths,
                          uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH,
                          bool allow_committee = false,
                          const flat_set<account_id_type>& active_aprovals = flat_set<account_id_type>(),
                          const flat_set<account_id_type>& owner_approvals = flat_set<account_id_type>() );

   /**
    *  @brief captures the result of evaluating the operations contained in the transaction
    *
    *  When processing a transaction some operations generate
    *  new object IDs and these IDs cannot be known until the
    *  transaction is actually included into a block.  When a
    *  block is produced these new ids are captured and included
    *  with every transaction.  The index in operation_results should
    *  correspond to the same index in operations.
    *
    *  If an operation did not create any new object IDs then 0
    *  should be returned.
    */
   struct processed_transaction : public precomputable_transaction
   {
      processed_transaction( const signed_transaction& trx = signed_transaction() )
         : precomputable_transaction(trx){}
      virtual ~processed_transaction() = default;

      vector<operation_result> operation_results;

      digest_type merkle_digest()const;
   };

   /// @} transactions group

} } // graphene::protocol

FC_REFLECT( graphene::protocol::transaction, (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions) )
// Note: not reflecting signees field for backward compatibility; in addition, it should not be in p2p messages
FC_REFLECT_DERIVED( graphene::protocol::signed_transaction, (graphene::protocol::transaction), (signatures) )
FC_REFLECT_DERIVED( graphene::protocol::precomputable_transaction, (graphene::protocol::signed_transaction), )
FC_REFLECT_DERIVED( graphene::protocol::processed_transaction, (graphene::protocol::precomputable_transaction), (operation_results) )

GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::signed_transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::precomputable_transaction)
GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::protocol::processed_transaction)
<|endoftext|>


<commit_before>#include "lemonbuddy.hpp"
#include "bar.hpp"
#include "utils/math.hpp"
#include "utils/macros.hpp"
#include "modules/volume.hpp"

using namespace modules;

VolumeModule::VolumeModule(std::string name_) : EventModule(name_)
{
  // Load configuration values {{{
  auto master_mixer = config::get<std::string>(name(), "master_mixer", "Master");
  auto speaker_mixer = config::get<std::string>(name(), "speaker_mixer", "");
  auto headphone_mixer = config::get<std::string>(name(), "headphone_mixer", "");

  this->headphone_ctrl_numid = config::get<int>(name(), "headphone_control_numid", -1);

  if (!headphone_mixer.empty() && this->headphone_ctrl_numid == -1)
    throw ModuleError("[VolumeModule] Missing required property value for \"headphone_control_numid\"...");
  else if (headphone_mixer.empty() && this->headphone_ctrl_numid != -1)
    throw ModuleError("[VolumeModule] Missing required property value for \"headphone_mixer\"...");

  if (string::lower(speaker_mixer) == "master")
    throw ModuleError("[VolumeModule] The \"Master\" mixer is already processed internally. Specify another mixer or comment out the \"speaker_mixer\" parameter...");
  if (string::lower(headphone_mixer) == "master")
    throw ModuleError("[VolumeModule] The \"Master\" mixer is already processed internally. Specify another mixer or comment out the \"headphone_mixer\" parameter...");
  // }}}

  // Setup mixers {{{
  auto create_mixer = [](std::string mixer_name)
  {
    std::unique_ptr<alsa::Mixer> mixer;

    try {
      mixer = std::make_unique<alsa::Mixer>(mixer_name);
    } catch (alsa::MixerError &e) {
      log_error("Failed to open \""+ mixer_name +"\" mixer => "+ ToStr(e.what()));
      mixer.reset();
    }

    return mixer;
  };

  this->master_mixer = create_mixer(master_mixer);

  if (!speaker_mixer.empty())
    this->speaker_mixer = create_mixer(speaker_mixer);
  if (!headphone_mixer.empty())
    this->headphone_mixer = create_mixer(headphone_mixer);

  if (!this->master_mixer && !this->speaker_mixer && !this->headphone_mixer) {
    this->stop();
    return;
  }

  if (this->headphone_mixer && this->headphone_ctrl_numid > -1) {
    try {
      this->headphone_ctrl = std::make_unique<alsa::ControlInterface>(this->headphone_ctrl_numid);
    } catch (alsa::ControlInterfaceError &e) {
      log_error("Failed to open headphone control interface => "+ ToStr(e.what()));
      this->headphone_ctrl.reset();
    }
  }
  // }}}

  // Add formats and elements {{{
  this->formatter->add(FORMAT_VOLUME, TAG_LABEL_VOLUME,
    { TAG_RAMP_VOLUME, TAG_LABEL_VOLUME, TAG_BAR_VOLUME });
  this->formatter->add(FORMAT_MUTED, TAG_LABEL_MUTED,
    { TAG_RAMP_VOLUME, TAG_LABEL_MUTED, TAG_BAR_VOLUME });

  if (this->formatter->has(TAG_BAR_VOLUME))
    this->bar_volume = drawtypes::get_config_bar(name(), get_tag_name(TAG_BAR_VOLUME));
  if (this->formatter->has(TAG_RAMP_VOLUME))
    this->ramp_volume = drawtypes::get_config_ramp(name(), get_tag_name(TAG_RAMP_VOLUME));
  if (this->formatter->has(TAG_LABEL_VOLUME, FORMAT_VOLUME)) {
    this->label_volume = drawtypes::get_optional_config_label(name(), get_tag_name(TAG_LABEL_VOLUME), "%percentage%");
    this->label_volume_tokenized = this->label_volume->clone();
  }
  if (this->formatter->has(TAG_LABEL_MUTED, FORMAT_MUTED)) {
    this->label_muted = drawtypes::get_optional_config_label(name(), get_tag_name(TAG_LABEL_MUTED), "%percentage%");
    this->label_muted_tokenized = this->label_muted->clone();
  }
  // }}}
}

VolumeModule::~VolumeModule()
{
  std::lock_guard<concurrency::SpinLock> lck(this->update_lock);
  this->master_mixer.reset();
  this->speaker_mixer.reset();
  this->headphone_mixer.reset();
  this->headphone_ctrl.reset();
}

bool VolumeModule::has_event()
{
  bool has_event = false;

  if (this->has_changed())
    has_event = true;

  try {
    if (!has_event && this->master_mixer)
      has_event |= this->master_mixer->wait(25);
    if (!has_event && this->speaker_mixer)
      has_event |= this->speaker_mixer->wait(25);
    if (!has_event && this->headphone_mixer)
      has_event |= this->headphone_mixer->wait(25);
    if (!has_event && this->headphone_ctrl)
      has_event |= this->headphone_ctrl->wait(25);
  } catch (alsa::Exception &e) {
    log_error(e.what());
  }

  return has_event;
}

bool VolumeModule::update()
{
  // Consume any other pending events
  this->has_changed = false;
  if (this->master_mixer)
    this->master_mixer->process_events();
  if (this->speaker_mixer)
    this->speaker_mixer->process_events();
  if (this->headphone_mixer)
    this->headphone_mixer->process_events();
  if (this->headphone_ctrl)
    this->headphone_ctrl->wait(0);

  int volume = 100;
  bool muted = false;

  if (this->master_mixer) {
    volume *= this->master_mixer->get_volume() / 100.0f;
    muted |= this->master_mixer->is_muted();
  }

  if (this->headphone_mixer && this->headphone_ctrl && this->headphone_ctrl->test_device_plugged()) {
    volume *= this->headphone_mixer->get_volume() / 100.0f;
    muted |= this->headphone_mixer->is_muted();
  } else if (this->speaker_mixer) {
    volume *= this->speaker_mixer->get_volume() / 100.0f;
    muted |= this->speaker_mixer->is_muted();
  }

  this->volume = volume;
  this->muted = muted;

  this->label_volume_tokenized->text = this->label_volume->text;
  this->label_volume_tokenized->replace_token("%percentage%", std::to_string(this->volume()) +"%");

  this->label_muted_tokenized->text = this->label_muted->text;
  this->label_muted_tokenized->replace_token("%percentage%", std::to_string(this->volume()) +"%");

  return true;
}

std::string VolumeModule::get_format()
{
  return this->muted() == true ? FORMAT_MUTED : FORMAT_VOLUME;
}

std::string VolumeModule::get_output()
{
  this->builder->cmd(Cmd::LEFT_CLICK, EVENT_TOGGLE_MUTE);

  if (!this->muted()) {
    if (this->volume() < 100)
      this->builder->cmd(Cmd::SCROLL_UP, EVENT_VOLUME_UP);
    if (this->volume() > 0)
      this->builder->cmd(Cmd::SCROLL_DOWN, EVENT_VOLUME_DOWN);
  }

  this->builder->node(this->Module::get_output());

  return this->builder->flush();
}

bool VolumeModule::build(Builder *builder, std::string tag)
{
  if (tag == TAG_BAR_VOLUME)
    builder->node(this->bar_volume, volume);
  else if (tag == TAG_RAMP_VOLUME)
    builder->node(this->ramp_volume, volume);
  else if (tag == TAG_LABEL_VOLUME)
    builder->node(this->label_volume_tokenized);
  else if (tag == TAG_LABEL_MUTED)
    builder->node(this->label_muted_tokenized);
  else
    return false;

  return true;
}

bool VolumeModule::handle_command(std::string cmd)
{
  if (cmd.length() < std::strlen(EVENT_PREFIX))
    return false;
  if (std::strncmp(cmd.c_str(), EVENT_PREFIX, 3) != 0)
    return false;

  std::lock_guard<concurrency::SpinLock> lck(this->update_lock);

  alsa::Mixer *master_mixer = nullptr;
  alsa::Mixer *other_mixer = nullptr;

  if (this->master_mixer)
    master_mixer = this->master_mixer.get();

  if (master_mixer == nullptr)
    return false;

  if (this->headphone_mixer && this->headphone_ctrl && this->headphone_ctrl->test_device_plugged())
    other_mixer = this->headphone_mixer.get();
  else if (this->speaker_mixer)
    other_mixer = this->speaker_mixer.get();

  // Toggle mute state
  if (std::strncmp(cmd.c_str(), EVENT_TOGGLE_MUTE, std::strlen(EVENT_TOGGLE_MUTE)) == 0) {
    master_mixer->set_mute(this->muted());

    if (other_mixer != nullptr)
      other_mixer->set_mute(this->muted());

  // Increase volume
  } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_UP, std::strlen(EVENT_VOLUME_UP)) == 0) {
    master_mixer->set_volume(math::cap<float>(master_mixer->get_volume() + 5, 0, 100));

    if (other_mixer != nullptr)
      other_mixer->set_volume(math::cap<float>(other_mixer->get_volume() + 5, 0, 100));

  // Decrease volume
  } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_DOWN, std::strlen(EVENT_VOLUME_DOWN)) == 0) {
    master_mixer->set_volume(math::cap<float>(master_mixer->get_volume() - 5, 0, 100));

    if (other_mixer != nullptr)
      other_mixer->set_volume(math::cap<float>(other_mixer->get_volume() - 5, 0, 100));

  } else {
    return false;
  }

  this->has_changed = true;

  return true;
}
<commit_msg>Fix volume ramp not working<commit_after>#include <iostream>
#include "lemonbuddy.hpp"
#include "bar.hpp"
#include "utils/math.hpp"
#include "utils/macros.hpp"
#include "modules/volume.hpp"

using namespace modules;
using namespace std;

VolumeModule::VolumeModule(std::string name_) : EventModule(name_)
{
  // Load configuration values {{{
  auto master_mixer = config::get<std::string>(name(), "master_mixer", "Master");
  auto speaker_mixer = config::get<std::string>(name(), "speaker_mixer", "");
  auto headphone_mixer = config::get<std::string>(name(), "headphone_mixer", "");

  this->headphone_ctrl_numid = config::get<int>(name(), "headphone_control_numid", -1);

  if (!headphone_mixer.empty() && this->headphone_ctrl_numid == -1)
    throw ModuleError("[VolumeModule] Missing required property value for \"headphone_control_numid\"...");
  else if (headphone_mixer.empty() && this->headphone_ctrl_numid != -1)
    throw ModuleError("[VolumeModule] Missing required property value for \"headphone_mixer\"...");

  if (string::lower(speaker_mixer) == "master")
    throw ModuleError("[VolumeModule] The \"Master\" mixer is already processed internally. Specify another mixer or comment out the \"speaker_mixer\" parameter...");
  if (string::lower(headphone_mixer) == "master")
    throw ModuleError("[VolumeModule] The \"Master\" mixer is already processed internally. Specify another mixer or comment out the \"headphone_mixer\" parameter...");
  // }}}

  // Setup mixers {{{
  auto create_mixer = [](std::string mixer_name)
  {
    std::unique_ptr<alsa::Mixer> mixer;

    try {
      mixer = std::make_unique<alsa::Mixer>(mixer_name);
    } catch (alsa::MixerError &e) {
      log_error("Failed to open \""+ mixer_name +"\" mixer => "+ ToStr(e.what()));
      mixer.reset();
    }

    return mixer;
  };

  this->master_mixer = create_mixer(master_mixer);

  if (!speaker_mixer.empty())
    this->speaker_mixer = create_mixer(speaker_mixer);
  if (!headphone_mixer.empty())
    this->headphone_mixer = create_mixer(headphone_mixer);

  if (!this->master_mixer && !this->speaker_mixer && !this->headphone_mixer) {
    this->stop();
    return;
  }

  if (this->headphone_mixer && this->headphone_ctrl_numid > -1) {
    try {
      this->headphone_ctrl = std::make_unique<alsa::ControlInterface>(this->headphone_ctrl_numid);
    } catch (alsa::ControlInterfaceError &e) {
      log_error("Failed to open headphone control interface => "+ ToStr(e.what()));
      this->headphone_ctrl.reset();
    }
  }
  // }}}

  // Add formats and elements {{{
  this->formatter->add(FORMAT_VOLUME, TAG_LABEL_VOLUME,
    { TAG_RAMP_VOLUME, TAG_LABEL_VOLUME, TAG_BAR_VOLUME });
  this->formatter->add(FORMAT_MUTED, TAG_LABEL_MUTED,
    { TAG_RAMP_VOLUME, TAG_LABEL_MUTED, TAG_BAR_VOLUME });

  if (this->formatter->has(TAG_BAR_VOLUME))
    this->bar_volume = drawtypes::get_config_bar(name(), get_tag_name(TAG_BAR_VOLUME));
  if (this->formatter->has(TAG_RAMP_VOLUME))
    this->ramp_volume = drawtypes::get_config_ramp(name(), get_tag_name(TAG_RAMP_VOLUME));
  if (this->formatter->has(TAG_LABEL_VOLUME, FORMAT_VOLUME)) {
    this->label_volume = drawtypes::get_optional_config_label(name(), get_tag_name(TAG_LABEL_VOLUME), "%percentage%");
    this->label_volume_tokenized = this->label_volume->clone();
  }
  if (this->formatter->has(TAG_LABEL_MUTED, FORMAT_MUTED)) {
    this->label_muted = drawtypes::get_optional_config_label(name(), get_tag_name(TAG_LABEL_MUTED), "%percentage%");
    this->label_muted_tokenized = this->label_muted->clone();
  }
  // }}}
}

VolumeModule::~VolumeModule()
{
  std::lock_guard<concurrency::SpinLock> lck(this->update_lock);
  this->master_mixer.reset();
  this->speaker_mixer.reset();
  this->headphone_mixer.reset();
  this->headphone_ctrl.reset();
}

bool VolumeModule::has_event()
{
  bool has_event = false;

  if (this->has_changed())
    has_event = true;

  try {
    if (!has_event && this->master_mixer)
      has_event |= this->master_mixer->wait(25);
    if (!has_event && this->speaker_mixer)
      has_event |= this->speaker_mixer->wait(25);
    if (!has_event && this->headphone_mixer)
      has_event |= this->headphone_mixer->wait(25);
    if (!has_event && this->headphone_ctrl)
      has_event |= this->headphone_ctrl->wait(25);
  } catch (alsa::Exception &e) {
    log_error(e.what());
  }

  return has_event;
}

bool VolumeModule::update()
{
  // Consume any other pending events
  this->has_changed = false;
  if (this->master_mixer)
    this->master_mixer->process_events();
  if (this->speaker_mixer)
    this->speaker_mixer->process_events();
  if (this->headphone_mixer)
    this->headphone_mixer->process_events();
  if (this->headphone_ctrl)
    this->headphone_ctrl->wait(0);

  int volume = 100;
  bool muted = false;

  if (this->master_mixer) {
    volume *= this->master_mixer->get_volume() / 100.0f;
    muted |= this->master_mixer->is_muted();
  }

  if (this->headphone_mixer && this->headphone_ctrl && this->headphone_ctrl->test_device_plugged()) {
    volume *= this->headphone_mixer->get_volume() / 100.0f;
    muted |= this->headphone_mixer->is_muted();
  } else if (this->speaker_mixer) {
    volume *= this->speaker_mixer->get_volume() / 100.0f;
    muted |= this->speaker_mixer->is_muted();
  }

  this->volume = volume;
  this->muted = muted;

  this->label_volume_tokenized->text = this->label_volume->text;
  this->label_volume_tokenized->replace_token("%percentage%", std::to_string(this->volume()) +"%");

  this->label_muted_tokenized->text = this->label_muted->text;
  this->label_muted_tokenized->replace_token("%percentage%", std::to_string(this->volume()) +"%");

  return true;
}

std::string VolumeModule::get_format()
{
  return this->muted() == true ? FORMAT_MUTED : FORMAT_VOLUME;
}

std::string VolumeModule::get_output()
{
  this->builder->cmd(Cmd::LEFT_CLICK, EVENT_TOGGLE_MUTE);

  if (!this->muted()) {
    if (this->volume() < 100)
      this->builder->cmd(Cmd::SCROLL_UP, EVENT_VOLUME_UP);
    if (this->volume() > 0)
      this->builder->cmd(Cmd::SCROLL_DOWN, EVENT_VOLUME_DOWN);
  }

  this->builder->node(this->Module::get_output());

  return this->builder->flush();
}

bool VolumeModule::build(Builder *builder, std::string tag)
{
  if (tag == TAG_BAR_VOLUME)
    builder->node(this->bar_volume, volume());
  else if (tag == TAG_RAMP_VOLUME)
    builder->node(this->ramp_volume, volume());
  else if (tag == TAG_LABEL_VOLUME)
    builder->node(this->label_volume_tokenized);
  else if (tag == TAG_LABEL_MUTED)
    builder->node(this->label_muted_tokenized);
  else
    return false;

  return true;
}

bool VolumeModule::handle_command(std::string cmd)
{
  if (cmd.length() < std::strlen(EVENT_PREFIX))
    return false;
  if (std::strncmp(cmd.c_str(), EVENT_PREFIX, 3) != 0)
    return false;

  std::lock_guard<concurrency::SpinLock> lck(this->update_lock);

  alsa::Mixer *master_mixer = nullptr;
  alsa::Mixer *other_mixer = nullptr;

  if (this->master_mixer)
    master_mixer = this->master_mixer.get();

  if (master_mixer == nullptr)
    return false;

  if (this->headphone_mixer && this->headphone_ctrl && this->headphone_ctrl->test_device_plugged())
    other_mixer = this->headphone_mixer.get();
  else if (this->speaker_mixer)
    other_mixer = this->speaker_mixer.get();

  // Toggle mute state
  if (std::strncmp(cmd.c_str(), EVENT_TOGGLE_MUTE, std::strlen(EVENT_TOGGLE_MUTE)) == 0) {
    master_mixer->set_mute(this->muted());

    if (other_mixer != nullptr)
      other_mixer->set_mute(this->muted());

  // Increase volume
  } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_UP, std::strlen(EVENT_VOLUME_UP)) == 0) {
    master_mixer->set_volume(math::cap<float>(master_mixer->get_volume() + 5, 0, 100));

    if (other_mixer != nullptr)
      other_mixer->set_volume(math::cap<float>(other_mixer->get_volume() + 5, 0, 100));

  // Decrease volume
  } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_DOWN, std::strlen(EVENT_VOLUME_DOWN)) == 0) {
    master_mixer->set_volume(math::cap<float>(master_mixer->get_volume() - 5, 0, 100));

    if (other_mixer != nullptr)
      other_mixer->set_volume(math::cap<float>(other_mixer->get_volume() - 5, 0, 100));

  } else {
    return false;
  }

  this->has_changed = true;

  return true;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/foreach.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/test/unit_test.hpp>
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"

#include "main.h"
#include "wallet.h"

using namespace std;
using namespace json_spirit;
using namespace boost::algorithm;

extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
                         bool fValidatePayToScriptHash, int nHashType);

CScript
ParseScript(string s)
{
    CScript result;

    static map<string, opcodetype> mapOpNames;

    if (mapOpNames.size() == 0)
    {
        for (int op = OP_NOP; op <= OP_NOP10; op++)
        {
            const char* name = GetOpName((opcodetype)op);
            if (strcmp(name, "OP_UNKNOWN") == 0)
                continue;
            string strName(name);
            mapOpNames[strName] = (opcodetype)op;
            // Convenience: OP_ADD and just ADD are both recognized:
            replace_first(strName, "OP_", "");
            mapOpNames[strName] = (opcodetype)op;
        }
    }

    vector<string> words;
    split(words, s, is_any_of(" \t\n"), token_compress_on);

    BOOST_FOREACH(string w, words)
    {
        if (all(w, is_digit()) ||
            (starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit())))
        {
            // Number
            int64 n = atoi64(w);
            result << n;
        }
        else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end())))
        {
            // Raw hex data, inserted NOT pushed onto stack:
            std::vector<unsigned char> raw = ParseHex(string(w.begin()+2, w.end()));
            result.insert(result.end(), raw.begin(), raw.end());
        }
        else if (w.size() >= 2 && starts_with(w, "'") && ends_with(w, "'"))
        {
            // Single-quoted string, pushed as data. NOTE: this is poor-man's
            // parsing, spaces/tabs/newlines in single-quoted strings won't work.
            std::vector<unsigned char> value(w.begin()+1, w.end()-1);
            result << value;
        }
        else if (mapOpNames.count(w))
        {
            // opcode, e.g. OP_ADD or OP_1:
            result << mapOpNames[w];
        }
        else
        {
            BOOST_ERROR("Parse error: " << s);
            return CScript();
        }
    }

    return result;
}

Array
read_json(const std::string& filename)
{
    namespace fs = boost::filesystem;
    fs::path testFile = fs::current_path() / "test" / "data" / filename;

#ifdef TEST_DATA_DIR
    if (!fs::exists(testFile))
    {
        testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename;
    }
#endif

    ifstream ifs(testFile.string().c_str(), ifstream::in);
    Value v;
    if (!read_stream(ifs, v))
    {
        if (ifs.fail())
            BOOST_ERROR("Cound not find/open " << filename);
        else
            BOOST_ERROR("JSON syntax error in " << filename);
        return Array();
    }
    if (v.type() != array_type)
    {
        BOOST_ERROR(filename << " does not contain a json array");
        return Array();
    }

    return v.get_array();
}

BOOST_AUTO_TEST_SUITE(script_tests)

BOOST_AUTO_TEST_CASE(script_valid)
{
    // Read tests from test/data/script_valid.json
    // Format is an array of arrays
    // Inner arrays are [ "scriptSig", "scriptPubKey" ]
    // ... where scriptSig and scriptPubKey are stringified
    // scripts.
    Array tests = read_json("script_valid.json");

    BOOST_FOREACH(Value& tv, tests)
    {
        Array test = tv.get_array();
        string strTest = write_string(tv, false);
        if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        string scriptSigString = test[0].get_str();
        CScript scriptSig = ParseScript(scriptSigString);
        string scriptPubKeyString = test[1].get_str();
        CScript scriptPubKey = ParseScript(scriptPubKeyString);

        CTransaction tx;
        BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
    }
}

BOOST_AUTO_TEST_CASE(script_invalid)
{
    // Scripts that should evaluate as invalid
    Array tests = read_json("script_invalid.json");

    BOOST_FOREACH(Value& tv, tests)
    {
        Array test = tv.get_array();
        string strTest = write_string(tv, false);
        if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
        string scriptSigString = test[0].get_str();
        CScript scriptSig = ParseScript(scriptSigString);
        string scriptPubKeyString = test[1].get_str();
        CScript scriptPubKey = ParseScript(scriptPubKeyString);

        CTransaction tx;
        BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest);
    }
}

BOOST_AUTO_TEST_CASE(script_PushData)
{
    // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
    // the stack as the 1-75 opcodes do.
    static const unsigned char direct[] = { 1, 0x5a };
    static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a };
    static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };
    static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };

    vector<vector<unsigned char> > directStack;
    BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0));

    vector<vector<unsigned char> > pushdata1Stack;
    BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0));
    BOOST_CHECK(pushdata1Stack == directStack);

    vector<vector<unsigned char> > pushdata2Stack;
    BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0));
    BOOST_CHECK(pushdata2Stack == directStack);

    vector<vector<unsigned char> > pushdata4Stack;
    BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0));
    BOOST_CHECK(pushdata4Stack == directStack);
}

CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
{
    uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL);

    CScript result;
    //
    // NOTE: CHECKMULTISIG has an unfortunate bug; it requires
    // one extra item on the stack, before the signatures.
    // Putting OP_0 on the stack is the workaround;
    // fixing the bug would mean splitting the blockchain (old
    // clients would not accept new CHECKMULTISIG transactions,
    // and vice-versa)
    //
    result << OP_0;
    BOOST_FOREACH(CKey key, keys)
    {
        vector<unsigned char> vchSig;
        BOOST_CHECK(key.Sign(hash, vchSig));
        vchSig.push_back((unsigned char)SIGHASH_ALL);
        result << vchSig;
    }
    return result;
}
CScript
sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
{
    std::vector<CKey> keys;
    keys.push_back(key);
    return sign_multisig(scriptPubKey, keys, transaction);
}

BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
{
    CKey key1, key2, key3;
    key1.MakeNewKey(true);
    key2.MakeNewKey(false);
    key3.MakeNewKey(true);

    CScript scriptPubKey12;
    scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;

    CTransaction txFrom12;
    txFrom12.vout.resize(1);
    txFrom12.vout[0].scriptPubKey = scriptPubKey12;

    CTransaction txTo12;
    txTo12.vin.resize(1);
    txTo12.vout.resize(1);
    txTo12.vin[0].prevout.n = 0;
    txTo12.vin[0].prevout.hash = txFrom12.GetHash();
    txTo12.vout[0].nValue = 1;

    CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));
    txTo12.vout[0].nValue = 2;
    BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0));

    CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0));

    CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0));
}

BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
{
    CKey key1, key2, key3, key4;
    key1.MakeNewKey(true);
    key2.MakeNewKey(false);
    key3.MakeNewKey(true);
    key4.MakeNewKey(false);

    CScript scriptPubKey23;
    scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;

    CTransaction txFrom23;
    txFrom23.vout.resize(1);
    txFrom23.vout[0].scriptPubKey = scriptPubKey23;

    CTransaction txTo23;
    txTo23.vin.resize(1);
    txTo23.vout.resize(1);
    txTo23.vin[0].prevout.n = 0;
    txTo23.vin[0].prevout.hash = txFrom23.GetHash();
    txTo23.vout[0].nValue = 1;

    std::vector<CKey> keys;
    keys.push_back(key1); keys.push_back(key2);
    CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key1); keys.push_back(key3);
    CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key2); keys.push_back(key3);
    CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
    CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
    CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
    CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
    CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear();
    keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
    CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, 0));

    keys.clear(); // Must have signatures
    CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
    BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0));
}

BOOST_AUTO_TEST_CASE(script_combineSigs)
{
    // Test the CombineSignatures function
    CBasicKeyStore keystore;
    vector<CKey> keys;
    for (int i = 0; i < 3; i++)
    {
        CKey key;
        key.MakeNewKey(i%2 == 1);
        keys.push_back(key);
        keystore.AddKey(key);
    }

    CTransaction txFrom;
    txFrom.vout.resize(1);
    txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID());
    CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
    CTransaction txTo;
    txTo.vin.resize(1);
    txTo.vout.resize(1);
    txTo.vin[0].prevout.n = 0;
    txTo.vin[0].prevout.hash = txFrom.GetHash();
    CScript& scriptSig = txTo.vin[0].scriptSig;
    txTo.vout[0].nValue = 1;

    CScript empty;
    CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty);
    BOOST_CHECK(combined.empty());

    // Single signature case:
    SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
    BOOST_CHECK(combined == scriptSig);
    combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
    BOOST_CHECK(combined == scriptSig);
    CScript scriptSigCopy = scriptSig;
    // Signing again will give a different, valid signature:
    SignSignature(keystore, txFrom, txTo, 0);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
    BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);

    // P2SH, single-signature case:
    CScript pkSingle; pkSingle << keys[0].GetPubKey() << OP_CHECKSIG;
    keystore.AddCScript(pkSingle);
    scriptPubKey.SetDestination(pkSingle.GetID());
    SignSignature(keystore, txFrom, txTo, 0);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
    BOOST_CHECK(combined == scriptSig);
    combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
    BOOST_CHECK(combined == scriptSig);
    scriptSigCopy = scriptSig;
    SignSignature(keystore, txFrom, txTo, 0);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
    BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
    // dummy scriptSigCopy with placeholder, should always choose non-placeholder:
    scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
    BOOST_CHECK(combined == scriptSig);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy);
    BOOST_CHECK(combined == scriptSig);

    // Hardest case:  Multisig 2-of-3
    scriptPubKey.SetMultisig(2, keys);
    keystore.AddCScript(scriptPubKey);
    SignSignature(keystore, txFrom, txTo, 0);
    combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
    BOOST_CHECK(combined == scriptSig);
    combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
    BOOST_CHECK(combined == scriptSig);

    // A couple of partially-signed versions:
    vector<unsigned char> sig1;
    uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL);
    BOOST_CHECK(keys[0].Sign(hash1, sig1));
    sig1.push_back(SIGHASH_ALL);
    vector<unsigned char> sig2;
    uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE);
    BOOST_CHECK(keys[1].Sign(hash2, sig2));
    sig2.push_back(SIGHASH_NONE);
    vector<unsigned char> sig3;
    uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE);
    BOOST_CHECK(keys[2].Sign(hash3, sig3));
    sig3.push_back(SIGHASH_SINGLE);

    // Not fussy about order (or even existence) of placeholders or signatures:
    CScript partial1a = CScript() << OP_0 << sig1 << OP_0;
    CScript partial1b = CScript() << OP_0 << OP_0 << sig1;
    CScript partial2a = CScript() << OP_0 << sig2;
    CScript partial2b = CScript() << sig2 << OP_0;
    CScript partial3a = CScript() << sig3;
    CScript partial3b = CScript() << OP_0 << OP_0 << sig3;
    CScript partial3c = CScript() << OP_0 << sig3 << OP_0;
    CScript complete12 = CScript() << OP_0 << sig1 << sig2;
    CScript complete13 = CScript() << OP_0 << sig1 << sig3;
    CScript complete23 = CScript() << OP_0 << sig2 << sig3;

    combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b);
    BOOST_CHECK(combined == partial1a);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a);
    BOOST_CHECK(combined == complete12);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a);
    BOOST_CHECK(combined == complete12);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b);
    BOOST_CHECK(combined == complete12);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b);
    BOOST_CHECK(combined == complete13);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a);
    BOOST_CHECK(combined == complete23);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b);
    BOOST_CHECK(combined == complete23);
    combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a);
    BOOST_CHECK(combined == partial3c);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Delete script_tests.cpp<commit_after><|endoftext|>


<commit_before>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     28
#define BUILD_NUMBER      39
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<commit_msg>[Auto-roll] Bump up version to 3.28.40.0<commit_after>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     28
#define BUILD_NUMBER      40
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

// Vivification is a special case of asymmetric tautology elimination.  It
// strengthens and removes irredundant clauses proven redundant through unit
// propagation.  The original algorithm is due to a paper by Piette, Hamadi
// published at ECAI'08.  We have an inprocessing version, e.g., it does not
// necessarily run-to-completion.  It does no conflict analysis and uses a
// new heuristic for selecting clauses to vivify.

/*------------------------------------------------------------------------*/

struct ClauseScore {
  Clause * clause;
  long score;
  ClauseScore (Clause * c) : clause (c), score (0) { }
};

struct less_clause_score {
  bool operator () (const ClauseScore & a, const ClauseScore & b) const {
    return a.score < b.score;
  }
};

struct less_negated_noccs2 {
  Internal * internal;
  less_negated_noccs2 (Internal * i) : internal (i) { }
  bool operator () (int a, int b) {
    long u = internal->noccs2 (-a), v = internal->noccs2 (-b);
    if (u < v) return true;
    if (u > v) return false;
    int i = abs (a), j = abs (b);
    if (i < j) return true;
    if (i > j) return false;
    return a < b;
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  assert (opts.vivify);

  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  vector<ClauseScore> schedule;

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  // After an arithmetic increasing number of calls to 'vivify' we
  // reschedule all clauses, instead of only those not tried before.  Then
  // this limit is increased by one. The argument is that we should focus on
  // clauses with many occurrences of their negated literals (also long
  // clauses), but in the limit eventually still should vivify all clauses.
  //
  bool reschedule_all = !lim.vivifywaitreset;
  if (reschedule_all) lim.vivifywaitreset = ++inc.vivifywaitreset;
  else lim.vivifywaitreset--;

  // In the first round check whether there are still clauses left, which
  // are scheduled to but have not been vivified yet.  In the second round
  // if no such clauses are found in the first round.  This is also
  // performed if rescheduling is forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;	// see also (NO-BINARY) below
      if (!reschedule_all && !round && !c->vivify) continue;
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, responsible for most of
  // the propagation usually.
  //
  init_noccs2 ();

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage) continue;
    if (c->redundant) continue;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs2 (*j)++;
  }

  // Then update the score of the candidate clauses by adding up the number
  // of occurrences of the negation of its literals.
  //
  const vector<ClauseScore>::const_iterator eos = schedule.end ();
  vector<ClauseScore>::iterator k;

  for (k = schedule.begin (); k != eos; k++) {
    ClauseScore & cs = *k;
    const const_literal_iterator eoc = cs.clause->end ();
    const_literal_iterator j;
    long score = 0;
    for (j = cs.clause->begin (); j != eoc; j++)
      score += noccs2 (-*j);
    cs.score = score;
  }

  // Then sort candidates, with best clause (many negative occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), less_clause_score ());

  long scheduled = schedule.size ();
  VRB ("vivification", stats.vivifications,
    "scheduled irredundant %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));

  // We need to make sure to propagate only over irredundant clauses.
  //
  flush_redundant_watches ();
  size_t old_propagated = propagated;

  long checked = 0, subsumed = 0, strengthened = 0, units = 0;
  vector<int> sorted;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = opts.vivifyreleff * stats.propagations.search;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ().clause;
    schedule.pop_back ();
    assert (c->vivify);
    c->vivify = false;

    assert (!c->garbage);
    assert (!c->redundant);
    assert (c->size > 2);
    assert (!level);

    // First check whether it is already satisfied.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool satisfied = false;

    sorted.clear ();

    for (j = c->begin (); !satisfied && j != eoc; j++) {
      const int lit = *j, tmp = val (lit);
      if (tmp > 0) satisfied = true;
      else if (!tmp) sorted.push_back (lit);
    }

    if (satisfied) { mark_garbage (c); continue; }

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // Sort the literals of the candidate with respect to the largest number
    // of negative occurrences.  The idea is that more negative occurrences
    // lead to more propagations and thus potentially higher earlier effect.
    //
    sort (sorted.begin (), sorted.end (), less_negated_noccs2 (this));

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses, e.g., ignoring binary clauses, without
    // changing 'propagate' and actually we also do not want to remove
    // binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead (TODO).
    //
    c->ignore = true;		// see also (NO-BINARY) above

    bool redundant = false;	// determined to be redundant / subsumed
    int remove = 0;		// at least literal 'remove' can be removed

    while (!redundant && !remove && !sorted.empty ()) {
      const int lit = sorted.back (), tmp = val (lit);
      sorted.pop_back ();
      if (tmp > 0) {
	LOG ("redundant since literal %d already true", lit);
	redundant = true;
      } else if (tmp < 0) {
	LOG ("removing at least literal %d which is already false", lit);
	remove = lit;
      } else {
	assume_decision (-lit);
	if (propagate ()) continue;
	LOG ("redundant since propagation produced conflict");
	redundant = true;
	conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      strengthened++;
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.
      //
      for (j = c->begin (); j != eoc; j++) {
	const int other = *j, tmp = val (other);
	Var & v = var (other);
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", other);
	  clause.clear ();
	  goto REDUNDANT;
	}
	if (tmp < 0 && !v.level) continue;
	if (tmp < 0 && v.level && v.reason) {
	  assert (v.level);
	  assert (v.reason);
	  LOG ("flushing literal %d", other);
	  mark_removed (other);
#ifndef NDEBUG
	  if (other == remove) found = true;
#endif
	} else clause.push_back (other);
      }
      assert (found);
      assert (!clause.empty ());
      backtrack ();
      if (clause.size () == 1) {
	const int unit = clause[0];
	LOG (c, "vivification shrunken to unit %d", unit);
	assert (!val (unit));
	assign_unit (unit);
	units++;
	bool ok = propagate ();
	if (!ok) learn_empty_clause ();
      } else {
#ifdef LOGGING
	Clause * d =
#endif
	new_clause_as (c);
	LOG (c, "before vivification");
	LOG (d, "after vivification");
      }
      clause.clear ();
      mark_garbage (c);
    }
    if (level) backtrack ();
    c->ignore = false;
  }

  if (!unsat) {
    erase_vector (sorted);
    reset_noccs2 ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();
    if (old_propagated < propagated) {
      propagated = old_propagated;
      if (!propagate ()) {
	LOG ("propagating vivified units leads to conflict");
	learn_empty_clause ();
      }
    }
  }

  VRB ("vivification", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  VRB ("vivification", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivification", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivification", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);
}

};
<commit_msg>commented on issue<commit_after>#include "internal.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

// Vivification is a special case of asymmetric tautology elimination.  It
// strengthens and removes irredundant clauses proven redundant through unit
// propagation.  The original algorithm is due to a paper by Piette, Hamadi
// published at ECAI'08.  We have an inprocessing version, e.g., it does not
// necessarily run-to-completion.  It does no conflict analysis and uses a
// new heuristic for selecting clauses to vivify.

/*------------------------------------------------------------------------*/

struct ClauseScore {
  Clause * clause;
  long score;
  ClauseScore (Clause * c) : clause (c), score (0) { }
};

struct less_clause_score {
  bool operator () (const ClauseScore & a, const ClauseScore & b) const {
    return a.score < b.score;
  }
};

struct less_negated_noccs2 {
  Internal * internal;
  less_negated_noccs2 (Internal * i) : internal (i) { }
  bool operator () (int a, int b) {
    long u = internal->noccs2 (-a), v = internal->noccs2 (-b);
    if (u < v) return true;
    if (u > v) return false;
    int i = abs (a), j = abs (b);
    if (i < j) return true;
    if (i > j) return false;
    return a < b;
  }
};

/*------------------------------------------------------------------------*/

void Internal::vivify () {

  assert (opts.vivify);

  SWITCH_AND_START (search, simplify, vivify);

  assert (!vivifying);
  vivifying = true;

  stats.vivifications++;
  if (level) backtrack ();

  vector<ClauseScore> schedule;

  const const_clause_iterator end = clauses.end ();
  const_clause_iterator i;

  // After an arithmetic increasing number of calls to 'vivify' we
  // reschedule all clauses, instead of only those not tried before.  Then
  // this limit is increased by one. The argument is that we should focus on
  // clauses with many occurrences of their negated literals (also long
  // clauses), but in the limit eventually still should vivify all clauses.
  //
  bool reschedule_all = !lim.vivifywaitreset;
  if (reschedule_all) lim.vivifywaitreset = ++inc.vivifywaitreset;
  else lim.vivifywaitreset--;

  // In the first round check whether there are still clauses left, which
  // are scheduled to but have not been vivified yet.  In the second round
  // if no such clauses are found in the first round.  This is also
  // performed if rescheduling is forced because 'reschedule_all' is  true.
  //
  for (int round = 0; schedule.empty () && round <= 1; round++) {
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      if (c->garbage) continue;
      if (c->redundant) continue;
      if (c->size == 2) continue;	// see also (NO-BINARY) below
      if (!reschedule_all && !round && !c->vivify) continue;
      schedule.push_back (c);
      c->vivify = true;
    }
  }
  shrink_vector (schedule);

  // Count the number of occurrences of literals in all irredundant clauses,
  // particularly the irredundant binary clauses, responsible for most of
  // the propagation usually.
  //
  init_noccs2 ();

  for (i = clauses.begin (); i != end; i++) {
    Clause * c = *i;
    if (c->garbage) continue;
    if (c->redundant) continue;
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    for (j = c->begin (); j != eoc; j++)
      noccs2 (*j)++;
  }

  // Then update the score of the candidate clauses by adding up the number
  // of occurrences of the negation of its literals.
  //
  const vector<ClauseScore>::const_iterator eos = schedule.end ();
  vector<ClauseScore>::iterator k;

  for (k = schedule.begin (); k != eos; k++) {
    ClauseScore & cs = *k;
    const const_literal_iterator eoc = cs.clause->end ();
    const_literal_iterator j;
    long score = 0;
    for (j = cs.clause->begin (); j != eoc; j++)
      score += noccs2 (-*j);
    cs.score = score;
  }

  // Then sort candidates, with best clause (many negative occurrences) last.
  //
  stable_sort (schedule.begin (), schedule.end (), less_clause_score ());

  long scheduled = schedule.size ();
  VRB ("vivification", stats.vivifications,
    "scheduled irredundant %ld clauses to be vivified %.0f%%",
    scheduled, percent (scheduled, stats.irredundant));

  // We need to make sure to propagate only over irredundant clauses.
  //
  flush_redundant_watches ();
  size_t old_propagated = propagated;	// see [RE-PROPAGATE] below.

  long checked = 0, subsumed = 0, strengthened = 0, units = 0;
  vector<int> sorted;

  // Limit the number of propagations during vivification as in 'probe'.
  //
  long delta = opts.vivifyreleff * stats.propagations.search;
  if (delta < opts.vivifymineff) delta = opts.vivifymineff;
  if (delta > opts.vivifymaxeff) delta = opts.vivifymaxeff;
  long limit = stats.propagations.vivify + delta;

  while (!unsat &&
         !schedule.empty () &&
         stats.propagations.vivify < limit) {

    // Next candidate clause to vivify.
    //
    Clause * c = schedule.back ().clause;
    schedule.pop_back ();
    assert (c->vivify);
    c->vivify = false;

    assert (!c->garbage);
    assert (!c->redundant);
    assert (c->size > 2);
    assert (!level);

    // First check whether it is already satisfied.
    //
    const const_literal_iterator eoc = c->end ();
    const_literal_iterator j;
    bool satisfied = false;

    sorted.clear ();

    for (j = c->begin (); !satisfied && j != eoc; j++) {
      const int lit = *j, tmp = val (lit);
      if (tmp > 0) satisfied = true;
      else if (!tmp) sorted.push_back (lit);
    }

    if (satisfied) { mark_garbage (c); continue; }

    // The actual vivification checking is performed here, by assuming the
    // negation of each of the remaining literals of the clause in turn and
    // propagating it.  If a conflict occurs or another literal in the
    // clause becomes assigned during propagation, we can stop.
    //
    LOG (c, "vivification checking");
    checked++;

    // Sort the literals of the candidate with respect to the largest number
    // of negative occurrences.  The idea is that more negative occurrences
    // lead to more propagations and thus potentially higher earlier effect.
    //
    sort (sorted.begin (), sorted.end (), less_negated_noccs2 (this));

    // Make sure to ignore this clause during propagation.  This is not that
    // easy for binary clauses, e.g., ignoring binary clauses, without
    // changing 'propagate' and actually we also do not want to remove
    // binary clauses which are subsumed.  Those are hyper binary
    // resolvents and should be kept as learned clauses instead (TODO).
    //
    c->ignore = true;		// see also (NO-BINARY) above

    bool redundant = false;	// determined to be redundant / subsumed
    int remove = 0;		// at least literal 'remove' can be removed

    while (!redundant && !remove && !sorted.empty ()) {
      const int lit = sorted.back (), tmp = val (lit);
      sorted.pop_back ();
      if (tmp > 0) {
	LOG ("redundant since literal %d already true", lit);
	redundant = true;
      } else if (tmp < 0) {
	LOG ("removing at least literal %d which is already false", lit);
	remove = lit;
      } else {
	assume_decision (-lit);
	if (propagate ()) continue;
	LOG ("redundant since propagation produced conflict");
	redundant = true;
	conflict = 0;
      }
    }

    if (redundant) {
REDUNDANT:
      subsumed++;
      LOG (c, "redundant asymmetric tautology");
      mark_garbage (c);
    } else if (remove) {
      strengthened++;
      assert (level);
      assert (clause.empty ());
#ifndef NDEBUG
      bool found = false;
#endif
      // There might be other literals implied to false (or even root level
      // falsified).  Those should be removed in addition to 'remove'.
      //
      for (j = c->begin (); j != eoc; j++) {
	const int other = *j, tmp = val (other);
	Var & v = var (other);
	if (tmp > 0) {
	  LOG ("redundant since literal %d already true", other);
	  clause.clear ();
	  goto REDUNDANT;
	}
	if (tmp < 0 && !v.level) continue;
	if (tmp < 0 && v.level && v.reason) {
	  assert (v.level);
	  assert (v.reason);
	  LOG ("flushing literal %d", other);
	  mark_removed (other);
#ifndef NDEBUG
	  if (other == remove) found = true;
#endif
	} else clause.push_back (other);
      }
      assert (found);
      assert (!clause.empty ());
      backtrack ();
      if (clause.size () == 1) {
	const int unit = clause[0];
	LOG (c, "vivification shrunken to unit %d", unit);
	assert (!val (unit));
	assign_unit (unit);
	units++;
	bool ok = propagate ();
	if (!ok) learn_empty_clause ();
      } else {
#ifdef LOGGING
	Clause * d =
#endif
	new_clause_as (c);
	LOG (c, "before vivification");
	LOG (d, "after vivification");
      }
      clause.clear ();
      mark_garbage (c);
    }
    if (level) backtrack ();
    c->ignore = false;
  }

  if (!unsat) {

    erase_vector (sorted);
    reset_noccs2 ();
    erase_vector (schedule);
    disconnect_watches ();
    connect_watches ();

    // [RE-PROPAGATE] Since redundant clause were disconnected during
    // propagating vivified units above, we have propagate all those fixed
    // literals again after connecting the redundant clauses back.
    // Otherwise, the invariants for watching and blocking literals break.
    //
    if (old_propagated < propagated) {
      propagated = old_propagated;
      if (!propagate ()) {
	LOG ("propagating vivified units leads to conflict");
	learn_empty_clause ();
      }
    }
  }

  VRB ("vivification", stats.vivifications,
    "checked %ld clauses %.02f%% out of scheduled",
    checked, percent (checked, scheduled));
  VRB ("vivification", stats.vivifications,
    "found %ld units %.02f%% out of checked",
    units, percent (units, checked));
  VRB ("vivification", stats.vivifications,
    "subsumed %ld clauses %.02f%% out of checked",
    subsumed, percent (subsumed, checked));
  VRB ("vivification", stats.vivifications,
    "strengthened %ld clauses %.02f%% out of checked",
    strengthened, percent (strengthened, checked));

  stats.vivifychecks += checked;
  stats.vivifysubs += subsumed;
  stats.vivifystrs += strengthened;
  stats.vivifyunits += units;

  stats.subsumed += subsumed;
  stats.strengthened += strengthened;

  assert (vivifying);
  vivifying = false;

  report ('v');
  STOP_AND_SWITCH (vivify, simplify, search);
}

};
<|endoftext|>