<commit_before>/*
 * Copyright (c) 2015 Intel Corporation.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "BLEPeripheral.h"

#include "BLECharacteristic.h"
#include "BLEDescriptor.h"
#include "BLEService.h"
#include "BLEUuid.h"

#define BLE_DISCONNECT_REASON_LOCAL_TERMINATION 0x16

void
blePeripheralGapEventHandler(ble_client_gap_event_t event, struct ble_gap_event *event_data, void *param)
{
    BLEPeripheral* p = (BLEPeripheral*)param;

    p->handleGapEvent(event, event_data);
}

void
blePeripheralGattsEventHandler(ble_client_gatts_event_t event, struct ble_gatts_evt_msg *event_data, void *param)
{
    BLEPeripheral* p = (BLEPeripheral*)param;

    p->handleGattsEvent(event, event_data);
}

BLEPeripheral::BLEPeripheral(void) :
    _state(BLE_PERIPH_STATE_NOT_READY),
    _advertise_service_uuid(NULL),
    _local_name(NULL),
    _appearance(0),
    _central(this),
    _attributes(NULL),
    _num_attributes(0),
    _last_added_characteritic(NULL)
{
    memset(_event_handlers, 0x00, sizeof(_event_handlers));

    ble_client_get_factory_config(&_local_bda, _device_name);
}

BLEPeripheral::~BLEPeripheral(void)
{
    if (this->_attributes) {
        free(this->_attributes);
    }
}

bool BLEPeripheral::begin()
{
    BleStatus status;

    status = _init();
    if (status != BLE_STATUS_SUCCESS) {
        return false;
    }

    /* Populate advertising data
     */
    _advDataInit();

    status = ble_client_gap_wr_adv_data(_adv_data, _adv_data_len);
    if (BLE_STATUS_SUCCESS != status) {
        return false;
    }

    uint16_t lastServiceHandle = 0;

    for (int i = 0; i < _num_attributes; i++) {
        BLEAttribute* attribute = _attributes[i];
        BLEAttributeType type = attribute->type();
        bool addResult = false;

        if (BLETypeService == type) {
            BLEService* service = (BLEService*)attribute;

            addResult = service->add();

            lastServiceHandle = service->handle();
        } else if (BLETypeCharacteristic == type) {
            BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

            addResult = characteristic->add(lastServiceHandle);
        } else if (BLETypeDescriptor == type) {
            BLEDescriptor *descriptor = (BLEDescriptor*)attribute;

            if (strcmp(descriptor->uuid(), "2901") == 0 ||
                strcmp(descriptor->uuid(), "2902") == 0 ||
                strcmp(descriptor->uuid(), "2903") == 0 ||
                strcmp(descriptor->uuid(), "2904") == 0) {
                continue; // skip
            }

            addResult = descriptor->add(lastServiceHandle);
        }

        if (!addResult) {
            return false;
        }
    }

    return (_startAdvertising() == BLE_STATUS_SUCCESS);
}

void
BLEPeripheral::poll()
{
    // no-op for now
    delay(1);
}

void
BLEPeripheral::end()
{
    _stop();
}

void
BLEPeripheral::setAdvertisedServiceUuid(const char* advertisedServiceUuid)
{
    _advertise_service_uuid = advertisedServiceUuid;
}

void
BLEPeripheral::setLocalName(const char* localName)
{
    _local_name = localName;
}

void
BLEPeripheral::setDeviceName(const char deviceName[])
{
    memset(_device_name, 0, sizeof(_device_name));
    if (_device_name && _device_name[0]) {
        int len = strlen(deviceName);
        if (len > BLE_MAX_DEVICE_NAME)
            len = BLE_MAX_DEVICE_NAME;
        memcpy(_device_name, deviceName, len);
    }
}

void
BLEPeripheral::setAppearance(const uint16_t appearance)
{
    _appearance = appearance;
}

void
BLEPeripheral::setEventHandler(BLEPeripheralEvent event, BLEPeripheralEventHandler callback)
{
  if (event < sizeof(_event_handlers)) {
    _event_handlers[event] = callback;
  }
}

void
BLEPeripheral::addAttribute(BLEAttribute& attribute)
{
    if (_attributes == NULL) {
        _attributes = (BLEAttribute**)malloc(BLEAttribute::numAttributes() * sizeof(BLEAttribute*));
    }

    _attributes[_num_attributes] = &attribute;
    _num_attributes++;

    BLEAttributeType type = attribute.type();

    if (BLETypeCharacteristic == type) {
        _last_added_characteritic = (BLECharacteristic*)&attribute;
    } else if (BLETypeDescriptor == type) {
        if (_last_added_characteritic) {
            BLEDescriptor* descriptor = (BLEDescriptor*)&attribute;

            if (strcmp("2901", descriptor->uuid()) == 0) {
                _last_added_characteritic->setUserDescription(descriptor);
            } else if (strcmp("2904", descriptor->uuid()) == 0) {
                _last_added_characteritic->setPresentationFormat(descriptor);
            }
        }
    }
}

bool
BLEPeripheral::disconnect()
{
    BleStatus status;

    if (BLE_PERIPH_STATE_CONNECTED == _state) {
        status = ble_client_gap_disconnect(BLE_DISCONNECT_REASON_LOCAL_TERMINATION);
    } else {
        status = BLE_STATUS_WRONG_STATE;
    }

    return (status == BLE_STATUS_SUCCESS);
}

BLECentral
BLEPeripheral::central()
{
    poll();

    return _central;
}

bool
BLEPeripheral::connected()
{
    poll();

    return _central;
}

BleStatus
BLEPeripheral::_init()
{
    BleStatus status;
    int8_t txPower = 127;

    if (BLE_PERIPH_STATE_NOT_READY != _state)
        return BLE_STATUS_WRONG_STATE;

    status = ble_client_init(blePeripheralGapEventHandler, this,
                             blePeripheralGattsEventHandler, this);
    if (BLE_STATUS_SUCCESS != status) {
        return status;
    }

    status = ble_client_gap_set_enable_config(_device_name, &_local_bda, _appearance, txPower);
    if (BLE_STATUS_SUCCESS != status) {
        return status;
    }

    _state = BLE_PERIPH_STATE_READY;
    return BLE_STATUS_SUCCESS;
}

void
BLEPeripheral::_advDataInit(void)
{
    uint8_t *adv_tmp = _adv_data;

    memset(_adv_data, 0, sizeof(_adv_data));

    /* Add flags */
    *adv_tmp++ = 2;
    *adv_tmp++ = BLE_ADV_TYPE_FLAGS;
    *adv_tmp++ = BLE_SVC_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    _adv_data_len = 3;

    if (_advertise_service_uuid) {
        BLEUuid bleUuid = BLEUuid(_advertise_service_uuid);
        struct bt_uuid uuid = bleUuid.uuid();

        if (BT_UUID16 == uuid.type) {
            uint8_t *adv_tmp = &_adv_data[_adv_data_len];
            *adv_tmp++ = (1 + sizeof(uint16_t)); /* Segment data length */
            *adv_tmp++ = BLE_ADV_TYPE_INC_16_UUID;
            UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16);
            _adv_data_len += (2 + sizeof(uint16_t));
        } else if (BT_UUID128 == uuid.type) {
            uint8_t *adv_tmp = &_adv_data[_adv_data_len];
            *adv_tmp++ = (1 + MAX_UUID_SIZE); /* Segment data length */
            *adv_tmp++ = BLE_ADV_TYPE_INC_128_UUID;
            memcpy(adv_tmp, uuid.uuid128, MAX_UUID_SIZE);
            _adv_data_len += (2 + MAX_UUID_SIZE);
        }
    }

    if (_local_name) {
        /* Add device name (truncated if too long) */
        uint8_t calculated_len;

        adv_tmp = &_adv_data[_adv_data_len];
        if (_adv_data_len + strlen(_local_name) + 2 <= BLE_MAX_ADV_SIZE) {
            *adv_tmp++ = strlen(_local_name) + 1;
            *adv_tmp++ = BLE_ADV_TYPE_COMP_LOCAL_NAME;
            calculated_len = strlen(_local_name);
        } else {
            *adv_tmp++ = BLE_MAX_ADV_SIZE - _adv_data_len - 1;
            *adv_tmp++ = BLE_ADV_TYPE_SHORT_LOCAL_NAME;
            calculated_len = BLE_MAX_ADV_SIZE - _adv_data_len - 2;
        }

        memcpy(adv_tmp, _local_name, calculated_len);
        _adv_data_len += calculated_len + 2;
    }
}

BleStatus
BLEPeripheral::_startAdvertising()
{
    BleStatus status;

    if (_state != BLE_PERIPH_STATE_READY)
        return BLE_STATUS_WRONG_STATE;

    status = ble_client_gap_start_advertise(0); // 0 = no timeout
    if (BLE_STATUS_SUCCESS != status)
        return status;

    _state = BLE_PERIPH_STATE_ADVERTISING;
    return BLE_STATUS_SUCCESS;
}

BleStatus
BLEPeripheral::_stop(void)
{
    BleStatus status;

    if (BLE_PERIPH_STATE_ADVERTISING == _state)
        status = ble_client_gap_stop_advertise();
    else
        status = disconnect();

    if (BLE_STATUS_SUCCESS != status)
        return status;

    _state = BLE_PERIPH_STATE_READY;
    return BLE_STATUS_SUCCESS;
}

void
BLEPeripheral::handleGapEvent(ble_client_gap_event_t event, struct ble_gap_event *event_data)
{
    if (BLE_CLIENT_GAP_EVENT_CONNECTED == event) {
        _state = BLE_PERIPH_STATE_CONNECTED;
        _central.setAddress(event_data->connected.peer_bda);

        if (_event_handlers[BLEConnected]) {
            _event_handlers[BLEConnected](_central);
        }
    } else if (BLE_CLIENT_GAP_EVENT_DISCONNECTED == event) {

        for (int i = 0; i < _num_attributes; i++) {
            BLEAttribute* attribute = _attributes[i];

            if (attribute->type() == BLETypeCharacteristic) {
                BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

                characteristic->setCccdValue(_central, 0x0000); // reset CCCD
            }
        }

        if (_event_handlers[BLEDisconnected])
            _event_handlers[BLEDisconnected](_central);

        _state = BLE_PERIPH_STATE_READY;
        _central.clearAddress();

        _startAdvertising();
    } else if (BLE_CLIENT_GAP_EVENT_CONN_TIMEOUT == event) {
        _state = BLE_PERIPH_STATE_READY;

        _startAdvertising();
    }
}

void
BLEPeripheral::handleGattsEvent(ble_client_gatts_event_t event, struct ble_gatts_evt_msg *event_data)
{
    if (BLE_CLIENT_GATTS_EVENT_WRITE == event) {
        uint16_t handle = event_data->wr.attr_handle;

        for (int i = 0; i < _num_attributes; i++) {
            BLEAttribute* attribute = _attributes[i];

            if (attribute->type() != BLETypeCharacteristic) {
                continue;
            }

            BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

            if (characteristic->valueHandle() == handle) {
                characteristic->setValue(_central, event_data->wr.data, event_data->wr.len);
                break;
            } else if (characteristic->cccdHandle() == handle) {
                uint16_t cccdValue = 0;

                memcpy(&cccdValue, event_data->wr.data, event_data->wr.len);

                characteristic->setCccdValue(_central, cccdValue);
                break;
            }
        }
    }
}
<commit_msg>Correct setDeviceName<commit_after>/*
 * Copyright (c) 2015 Intel Corporation.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "BLEPeripheral.h"

#include "BLECharacteristic.h"
#include "BLEDescriptor.h"
#include "BLEService.h"
#include "BLEUuid.h"

#define BLE_DISCONNECT_REASON_LOCAL_TERMINATION 0x16

void
blePeripheralGapEventHandler(ble_client_gap_event_t event, struct ble_gap_event *event_data, void *param)
{
    BLEPeripheral* p = (BLEPeripheral*)param;

    p->handleGapEvent(event, event_data);
}

void
blePeripheralGattsEventHandler(ble_client_gatts_event_t event, struct ble_gatts_evt_msg *event_data, void *param)
{
    BLEPeripheral* p = (BLEPeripheral*)param;

    p->handleGattsEvent(event, event_data);
}

BLEPeripheral::BLEPeripheral(void) :
    _state(BLE_PERIPH_STATE_NOT_READY),
    _advertise_service_uuid(NULL),
    _local_name(NULL),
    _appearance(0),
    _central(this),
    _attributes(NULL),
    _num_attributes(0),
    _last_added_characteritic(NULL)
{
    memset(_event_handlers, 0x00, sizeof(_event_handlers));

    ble_client_get_factory_config(&_local_bda, _device_name);
}

BLEPeripheral::~BLEPeripheral(void)
{
    if (this->_attributes) {
        free(this->_attributes);
    }
}

bool BLEPeripheral::begin()
{
    BleStatus status;

    status = _init();
    if (status != BLE_STATUS_SUCCESS) {
        return false;
    }

    /* Populate advertising data
     */
    _advDataInit();

    status = ble_client_gap_wr_adv_data(_adv_data, _adv_data_len);
    if (BLE_STATUS_SUCCESS != status) {
        return false;
    }

    uint16_t lastServiceHandle = 0;

    for (int i = 0; i < _num_attributes; i++) {
        BLEAttribute* attribute = _attributes[i];
        BLEAttributeType type = attribute->type();
        bool addResult = false;

        if (BLETypeService == type) {
            BLEService* service = (BLEService*)attribute;

            addResult = service->add();

            lastServiceHandle = service->handle();
        } else if (BLETypeCharacteristic == type) {
            BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

            addResult = characteristic->add(lastServiceHandle);
        } else if (BLETypeDescriptor == type) {
            BLEDescriptor *descriptor = (BLEDescriptor*)attribute;

            if (strcmp(descriptor->uuid(), "2901") == 0 ||
                strcmp(descriptor->uuid(), "2902") == 0 ||
                strcmp(descriptor->uuid(), "2903") == 0 ||
                strcmp(descriptor->uuid(), "2904") == 0) {
                continue; // skip
            }

            addResult = descriptor->add(lastServiceHandle);
        }

        if (!addResult) {
            return false;
        }
    }

    return (_startAdvertising() == BLE_STATUS_SUCCESS);
}

void
BLEPeripheral::poll()
{
    // no-op for now
    delay(1);
}

void
BLEPeripheral::end()
{
    _stop();
}

void
BLEPeripheral::setAdvertisedServiceUuid(const char* advertisedServiceUuid)
{
    _advertise_service_uuid = advertisedServiceUuid;
}

void
BLEPeripheral::setLocalName(const char* localName)
{
    _local_name = localName;
}

void
BLEPeripheral::setDeviceName(const char deviceName[])
{
    memset(_device_name, 0, sizeof(_device_name));
    if (deviceName && deviceName[0]) {
        int len = strlen(deviceName);
        if (len > BLE_MAX_DEVICE_NAME)
            len = BLE_MAX_DEVICE_NAME;
        memcpy(_device_name, deviceName, len);
    }
}

void
BLEPeripheral::setAppearance(const uint16_t appearance)
{
    _appearance = appearance;
}

void
BLEPeripheral::setEventHandler(BLEPeripheralEvent event, BLEPeripheralEventHandler callback)
{
  if (event < sizeof(_event_handlers)) {
    _event_handlers[event] = callback;
  }
}

void
BLEPeripheral::addAttribute(BLEAttribute& attribute)
{
    if (_attributes == NULL) {
        _attributes = (BLEAttribute**)malloc(BLEAttribute::numAttributes() * sizeof(BLEAttribute*));
    }

    _attributes[_num_attributes] = &attribute;
    _num_attributes++;

    BLEAttributeType type = attribute.type();

    if (BLETypeCharacteristic == type) {
        _last_added_characteritic = (BLECharacteristic*)&attribute;
    } else if (BLETypeDescriptor == type) {
        if (_last_added_characteritic) {
            BLEDescriptor* descriptor = (BLEDescriptor*)&attribute;

            if (strcmp("2901", descriptor->uuid()) == 0) {
                _last_added_characteritic->setUserDescription(descriptor);
            } else if (strcmp("2904", descriptor->uuid()) == 0) {
                _last_added_characteritic->setPresentationFormat(descriptor);
            }
        }
    }
}

bool
BLEPeripheral::disconnect()
{
    BleStatus status;

    if (BLE_PERIPH_STATE_CONNECTED == _state) {
        status = ble_client_gap_disconnect(BLE_DISCONNECT_REASON_LOCAL_TERMINATION);
    } else {
        status = BLE_STATUS_WRONG_STATE;
    }

    return (status == BLE_STATUS_SUCCESS);
}

BLECentral
BLEPeripheral::central()
{
    poll();

    return _central;
}

bool
BLEPeripheral::connected()
{
    poll();

    return _central;
}

BleStatus
BLEPeripheral::_init()
{
    BleStatus status;
    int8_t txPower = 127;

    if (BLE_PERIPH_STATE_NOT_READY != _state)
        return BLE_STATUS_WRONG_STATE;

    status = ble_client_init(blePeripheralGapEventHandler, this,
                             blePeripheralGattsEventHandler, this);
    if (BLE_STATUS_SUCCESS != status) {
        return status;
    }

    status = ble_client_gap_set_enable_config(_device_name, &_local_bda, _appearance, txPower);
    if (BLE_STATUS_SUCCESS != status) {
        return status;
    }

    _state = BLE_PERIPH_STATE_READY;
    return BLE_STATUS_SUCCESS;
}

void
BLEPeripheral::_advDataInit(void)
{
    uint8_t *adv_tmp = _adv_data;

    memset(_adv_data, 0, sizeof(_adv_data));

    /* Add flags */
    *adv_tmp++ = 2;
    *adv_tmp++ = BLE_ADV_TYPE_FLAGS;
    *adv_tmp++ = BLE_SVC_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    _adv_data_len = 3;

    if (_advertise_service_uuid) {
        BLEUuid bleUuid = BLEUuid(_advertise_service_uuid);
        struct bt_uuid uuid = bleUuid.uuid();

        if (BT_UUID16 == uuid.type) {
            uint8_t *adv_tmp = &_adv_data[_adv_data_len];
            *adv_tmp++ = (1 + sizeof(uint16_t)); /* Segment data length */
            *adv_tmp++ = BLE_ADV_TYPE_INC_16_UUID;
            UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16);
            _adv_data_len += (2 + sizeof(uint16_t));
        } else if (BT_UUID128 == uuid.type) {
            uint8_t *adv_tmp = &_adv_data[_adv_data_len];
            *adv_tmp++ = (1 + MAX_UUID_SIZE); /* Segment data length */
            *adv_tmp++ = BLE_ADV_TYPE_INC_128_UUID;
            memcpy(adv_tmp, uuid.uuid128, MAX_UUID_SIZE);
            _adv_data_len += (2 + MAX_UUID_SIZE);
        }
    }

    if (_local_name) {
        /* Add device name (truncated if too long) */
        uint8_t calculated_len;

        adv_tmp = &_adv_data[_adv_data_len];
        if (_adv_data_len + strlen(_local_name) + 2 <= BLE_MAX_ADV_SIZE) {
            *adv_tmp++ = strlen(_local_name) + 1;
            *adv_tmp++ = BLE_ADV_TYPE_COMP_LOCAL_NAME;
            calculated_len = strlen(_local_name);
        } else {
            *adv_tmp++ = BLE_MAX_ADV_SIZE - _adv_data_len - 1;
            *adv_tmp++ = BLE_ADV_TYPE_SHORT_LOCAL_NAME;
            calculated_len = BLE_MAX_ADV_SIZE - _adv_data_len - 2;
        }

        memcpy(adv_tmp, _local_name, calculated_len);
        _adv_data_len += calculated_len + 2;
    }
}

BleStatus
BLEPeripheral::_startAdvertising()
{
    BleStatus status;

    if (_state != BLE_PERIPH_STATE_READY)
        return BLE_STATUS_WRONG_STATE;

    status = ble_client_gap_start_advertise(0); // 0 = no timeout
    if (BLE_STATUS_SUCCESS != status)
        return status;

    _state = BLE_PERIPH_STATE_ADVERTISING;
    return BLE_STATUS_SUCCESS;
}

BleStatus
BLEPeripheral::_stop(void)
{
    BleStatus status;

    if (BLE_PERIPH_STATE_ADVERTISING == _state)
        status = ble_client_gap_stop_advertise();
    else
        status = disconnect();

    if (BLE_STATUS_SUCCESS != status)
        return status;

    _state = BLE_PERIPH_STATE_READY;
    return BLE_STATUS_SUCCESS;
}

void
BLEPeripheral::handleGapEvent(ble_client_gap_event_t event, struct ble_gap_event *event_data)
{
    if (BLE_CLIENT_GAP_EVENT_CONNECTED == event) {
        _state = BLE_PERIPH_STATE_CONNECTED;
        _central.setAddress(event_data->connected.peer_bda);

        if (_event_handlers[BLEConnected]) {
            _event_handlers[BLEConnected](_central);
        }
    } else if (BLE_CLIENT_GAP_EVENT_DISCONNECTED == event) {

        for (int i = 0; i < _num_attributes; i++) {
            BLEAttribute* attribute = _attributes[i];

            if (attribute->type() == BLETypeCharacteristic) {
                BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

                characteristic->setCccdValue(_central, 0x0000); // reset CCCD
            }
        }

        if (_event_handlers[BLEDisconnected])
            _event_handlers[BLEDisconnected](_central);

        _state = BLE_PERIPH_STATE_READY;
        _central.clearAddress();

        _startAdvertising();
    } else if (BLE_CLIENT_GAP_EVENT_CONN_TIMEOUT == event) {
        _state = BLE_PERIPH_STATE_READY;

        _startAdvertising();
    }
}

void
BLEPeripheral::handleGattsEvent(ble_client_gatts_event_t event, struct ble_gatts_evt_msg *event_data)
{
    if (BLE_CLIENT_GATTS_EVENT_WRITE == event) {
        uint16_t handle = event_data->wr.attr_handle;

        for (int i = 0; i < _num_attributes; i++) {
            BLEAttribute* attribute = _attributes[i];

            if (attribute->type() != BLETypeCharacteristic) {
                continue;
            }

            BLECharacteristic* characteristic = (BLECharacteristic*)attribute;

            if (characteristic->valueHandle() == handle) {
                characteristic->setValue(_central, event_data->wr.data, event_data->wr.len);
                break;
            } else if (characteristic->cccdHandle() == handle) {
                uint16_t cccdValue = 0;

                memcpy(&cccdValue, event_data->wr.data, event_data->wr.len);

                characteristic->setCccdValue(_central, cccdValue);
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>#include <bts/blockchain/chain_interface.hpp>
#include <bts/blockchain/exceptions.hpp>

#include <algorithm>
#include <locale>

namespace bts{ namespace blockchain {

   balance_record::balance_record( const address& owner, const asset& balance_arg, slate_id_type delegate_id )
   {
      balance =  balance_arg.amount;
      condition = withdraw_condition( withdraw_with_signature( owner ), balance_arg.asset_id, delegate_id );
   }

   /** returns 0 if asset id is not condition.asset_id */
   asset balance_record::get_balance()const
   {
      return asset( balance, condition.asset_id );
   }

   address balance_record::owner()const
   {
      if( condition.type == withdraw_signature_type )
         return condition.as<withdraw_with_signature>().owner;
      return address();
   }

   share_type chain_interface::get_delegate_registration_fee()const
   {
      return (get_delegate_pay_rate() * BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE)/BTS_BLOCKCHAIN_NUM_DELEGATES;
   }

   share_type chain_interface::get_asset_registration_fee()const
   {
      return (get_delegate_pay_rate() * BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE);
   }

   share_type chain_interface::calculate_data_fee(size_t bytes) const
   {
      return (get_fee_rate() * bytes)/1000;
   }

   bool chain_interface::is_valid_account_name( const std::string& str )const
   {
      if( str.size() < BTS_BLOCKCHAIN_MIN_NAME_SIZE ) return false;
      if( str.size() > BTS_BLOCKCHAIN_MAX_NAME_SIZE ) return false;
      if( !isalpha(str[0]) ) return false;
      if ( !isalnum(str[str.size()-1]) || isupper(str[str.size()]) ) return false;

      std::string subname(str);
      std::string supername;
      int dot = str.find('.');
      if( dot != std::string::npos )
      {
        subname = str.substr(0, dot);
        //There is definitely a remainder; we checked above that the last character is not a dot
        supername = str.substr(dot+1);
      }

      if ( !isalnum(subname[subname.size()-1]) || isupper(subname[subname.size()-1]) ) return false;
      for( const auto& c : subname )
      {
          if( isalnum(c) && islower(c) ) continue;
          else if( c == '-' ) continue;
          else return false;
      }

      if( supername.empty() )
        return true;
      return is_valid_account_name(supername);
   }

   asset_id_type chain_interface::last_asset_id()const
   {
       return get_property( chain_property_enum::last_asset_id ).as<asset_id_type>();
   }

   asset_id_type  chain_interface::new_asset_id()
   {
      auto next_id = last_asset_id() + 1;
      set_property( chain_property_enum::last_asset_id, next_id );
      return next_id;
   }

   account_id_type   chain_interface::last_account_id()const
   {
       return get_property( chain_property_enum::last_account_id ).as<account_id_type>();
   }

   account_id_type   chain_interface::new_account_id()
   {
      auto next_id = last_account_id() + 1;
      set_property( chain_property_enum::last_account_id, next_id );
      return next_id;
   }

   proposal_id_type   chain_interface::last_proposal_id()const
   {
       return get_property( chain_property_enum::last_proposal_id ).as<proposal_id_type>();
   }

   proposal_id_type   chain_interface::new_proposal_id()
   {
      auto next_id = last_proposal_id() + 1;
      set_property( chain_property_enum::last_proposal_id, next_id );
      return next_id;
   }

   vector<account_id_type> chain_interface::get_active_delegates()const
   { try {
      return get_property( active_delegate_list_id ).as<std::vector<account_id_type>>();
   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   void chain_interface::set_active_delegates( const std::vector<account_id_type>& delegate_ids )
   {
      set_property( active_delegate_list_id, fc::variant(delegate_ids) );
   }

   bool chain_interface::is_active_delegate( account_id_type delegate_id ) const
   { try {
      auto active = get_active_delegates();
      return active.end() != std::find( active.begin(), active.end(), delegate_id );
   } FC_RETHROW_EXCEPTIONS( warn, "", ("delegate_id",delegate_id) ) }

   string chain_interface::to_pretty_price( const price& price_to_pretty_print )const
   { try {
      auto obase_asset = get_asset_record( price_to_pretty_print.base_asset_id );
      if( !obase_asset ) FC_CAPTURE_AND_THROW( unknown_asset_id, (price_to_pretty_print.base_asset_id) );

      auto oquote_asset = get_asset_record( price_to_pretty_print.quote_asset_id );
      if( !oquote_asset ) FC_CAPTURE_AND_THROW( unknown_asset_id, (price_to_pretty_print.quote_asset_id) );

      auto tmp = price_to_pretty_print;
      tmp.ratio *= obase_asset->get_precision();
      tmp.ratio /= oquote_asset->get_precision();

      return tmp.ratio_string() + " " + oquote_asset->symbol + " / " + obase_asset->symbol;

   } FC_CAPTURE_AND_RETHROW( (price_to_pretty_print) ) }

   string chain_interface::to_pretty_asset( const asset& a )const
   {
      const auto oasset = get_asset_record( a.asset_id );
      const auto amount = ( a.amount >= 0 ) ? a.amount : -a.amount;
      if( oasset.valid() )
      {
         const auto precision = oasset->get_precision();
         string decimal = fc::to_string( precision + ( amount % precision ) );
         decimal[0] = '.';
         const auto str = fc::to_pretty_string( amount / precision ) + decimal + " " + oasset->symbol;
         if( a.amount < 0 ) return "-" + str;
         return str;
      }
      else
      {
         return fc::to_pretty_string( a.amount ) + " ???";
      }
   }

   int64_t   chain_interface::get_required_confirmations()const
   {
      return get_property( confirmation_requirement ).as_int64();
   }

   bool chain_interface::is_valid_symbol_name( const string& name )const
   {
      if( name.size() > BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE )
         return false;
      if( name.size() < BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE )
         return false;
      std::locale loc;
      for( const auto& c : name )
         if( !std::isalnum(c,loc) || !std::isupper(c,loc) )
            return false;
      return true;
   }

   share_type  chain_interface::get_delegate_pay_rate()const
   {
      return get_accumulated_fees() / (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*14);
   }

   share_type  chain_interface::get_accumulated_fees()const
   {
      return get_property( accumulated_fees ).as_int64();
   }

   void  chain_interface::set_accumulated_fees( share_type fees )
   {
      set_property( accumulated_fees, variant(fees) );
   }
   share_type  chain_interface::get_fee_rate()const
   {
      return get_property( current_fee_rate ).as_int64();
   }

   void  chain_interface::set_fee_rate( share_type fees )
   {
      set_property( current_fee_rate, variant(fees) );
   }

   map<asset_id_type, asset_id_type>  chain_interface::get_dirty_markets()const
   {
      try{
         return get_property( dirty_markets ).as<map<asset_id_type,asset_id_type> >();
      } catch ( ... )
      {
         return map<asset_id_type,asset_id_type>();
      }
   }
   void  chain_interface::set_dirty_markets( const map<asset_id_type,asset_id_type>& d )
   {
      set_property( dirty_markets, fc::variant(d) );
   }

} } // bts::blockchain
<commit_msg>Fix off-by-one error<commit_after>#include <bts/blockchain/chain_interface.hpp>
#include <bts/blockchain/exceptions.hpp>

#include <algorithm>
#include <locale>

namespace bts{ namespace blockchain {

   balance_record::balance_record( const address& owner, const asset& balance_arg, slate_id_type delegate_id )
   {
      balance =  balance_arg.amount;
      condition = withdraw_condition( withdraw_with_signature( owner ), balance_arg.asset_id, delegate_id );
   }

   /** returns 0 if asset id is not condition.asset_id */
   asset balance_record::get_balance()const
   {
      return asset( balance, condition.asset_id );
   }

   address balance_record::owner()const
   {
      if( condition.type == withdraw_signature_type )
         return condition.as<withdraw_with_signature>().owner;
      return address();
   }

   share_type chain_interface::get_delegate_registration_fee()const
   {
      return (get_delegate_pay_rate() * BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE)/BTS_BLOCKCHAIN_NUM_DELEGATES;
   }

   share_type chain_interface::get_asset_registration_fee()const
   {
      return (get_delegate_pay_rate() * BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE);
   }

   share_type chain_interface::calculate_data_fee(size_t bytes) const
   {
      return (get_fee_rate() * bytes)/1000;
   }

   bool chain_interface::is_valid_account_name( const std::string& str )const
   {
      if( str.size() < BTS_BLOCKCHAIN_MIN_NAME_SIZE ) return false;
      if( str.size() > BTS_BLOCKCHAIN_MAX_NAME_SIZE ) return false;
      if( !isalpha(str[0]) ) return false;
      if ( !isalnum(str[str.size()-1]) || isupper(str[str.size()-1]) ) return false;

      std::string subname(str);
      std::string supername;
      int dot = str.find('.');
      if( dot != std::string::npos )
      {
        subname = str.substr(0, dot);
        //There is definitely a remainder; we checked above that the last character is not a dot
        supername = str.substr(dot+1);
      }

      if ( !isalnum(subname[subname.size()-1]) || isupper(subname[subname.size()-1]) ) return false;
      for( const auto& c : subname )
      {
          if( isalnum(c) && islower(c) ) continue;
          else if( c == '-' ) continue;
          else return false;
      }

      if( supername.empty() )
        return true;
      return is_valid_account_name(supername);
   }

   asset_id_type chain_interface::last_asset_id()const
   {
       return get_property( chain_property_enum::last_asset_id ).as<asset_id_type>();
   }

   asset_id_type  chain_interface::new_asset_id()
   {
      auto next_id = last_asset_id() + 1;
      set_property( chain_property_enum::last_asset_id, next_id );
      return next_id;
   }

   account_id_type   chain_interface::last_account_id()const
   {
       return get_property( chain_property_enum::last_account_id ).as<account_id_type>();
   }

   account_id_type   chain_interface::new_account_id()
   {
      auto next_id = last_account_id() + 1;
      set_property( chain_property_enum::last_account_id, next_id );
      return next_id;
   }

   proposal_id_type   chain_interface::last_proposal_id()const
   {
       return get_property( chain_property_enum::last_proposal_id ).as<proposal_id_type>();
   }

   proposal_id_type   chain_interface::new_proposal_id()
   {
      auto next_id = last_proposal_id() + 1;
      set_property( chain_property_enum::last_proposal_id, next_id );
      return next_id;
   }

   vector<account_id_type> chain_interface::get_active_delegates()const
   { try {
      return get_property( active_delegate_list_id ).as<std::vector<account_id_type>>();
   } FC_RETHROW_EXCEPTIONS( warn, "" ) }

   void chain_interface::set_active_delegates( const std::vector<account_id_type>& delegate_ids )
   {
      set_property( active_delegate_list_id, fc::variant(delegate_ids) );
   }

   bool chain_interface::is_active_delegate( account_id_type delegate_id ) const
   { try {
      auto active = get_active_delegates();
      return active.end() != std::find( active.begin(), active.end(), delegate_id );
   } FC_RETHROW_EXCEPTIONS( warn, "", ("delegate_id",delegate_id) ) }

   string chain_interface::to_pretty_price( const price& price_to_pretty_print )const
   { try {
      auto obase_asset = get_asset_record( price_to_pretty_print.base_asset_id );
      if( !obase_asset ) FC_CAPTURE_AND_THROW( unknown_asset_id, (price_to_pretty_print.base_asset_id) );

      auto oquote_asset = get_asset_record( price_to_pretty_print.quote_asset_id );
      if( !oquote_asset ) FC_CAPTURE_AND_THROW( unknown_asset_id, (price_to_pretty_print.quote_asset_id) );

      auto tmp = price_to_pretty_print;
      tmp.ratio *= obase_asset->get_precision();
      tmp.ratio /= oquote_asset->get_precision();

      return tmp.ratio_string() + " " + oquote_asset->symbol + " / " + obase_asset->symbol;

   } FC_CAPTURE_AND_RETHROW( (price_to_pretty_print) ) }

   string chain_interface::to_pretty_asset( const asset& a )const
   {
      const auto oasset = get_asset_record( a.asset_id );
      const auto amount = ( a.amount >= 0 ) ? a.amount : -a.amount;
      if( oasset.valid() )
      {
         const auto precision = oasset->get_precision();
         string decimal = fc::to_string( precision + ( amount % precision ) );
         decimal[0] = '.';
         const auto str = fc::to_pretty_string( amount / precision ) + decimal + " " + oasset->symbol;
         if( a.amount < 0 ) return "-" + str;
         return str;
      }
      else
      {
         return fc::to_pretty_string( a.amount ) + " ???";
      }
   }

   int64_t   chain_interface::get_required_confirmations()const
   {
      return get_property( confirmation_requirement ).as_int64();
   }

   bool chain_interface::is_valid_symbol_name( const string& name )const
   {
      if( name.size() > BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE )
         return false;
      if( name.size() < BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE )
         return false;
      std::locale loc;
      for( const auto& c : name )
         if( !std::isalnum(c,loc) || !std::isupper(c,loc) )
            return false;
      return true;
   }

   share_type  chain_interface::get_delegate_pay_rate()const
   {
      return get_accumulated_fees() / (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*14);
   }

   share_type  chain_interface::get_accumulated_fees()const
   {
      return get_property( accumulated_fees ).as_int64();
   }

   void  chain_interface::set_accumulated_fees( share_type fees )
   {
      set_property( accumulated_fees, variant(fees) );
   }
   share_type  chain_interface::get_fee_rate()const
   {
      return get_property( current_fee_rate ).as_int64();
   }

   void  chain_interface::set_fee_rate( share_type fees )
   {
      set_property( current_fee_rate, variant(fees) );
   }

   map<asset_id_type, asset_id_type>  chain_interface::get_dirty_markets()const
   {
      try{
         return get_property( dirty_markets ).as<map<asset_id_type,asset_id_type> >();
      } catch ( ... )
      {
         return map<asset_id_type,asset_id_type>();
      }
   }
   void  chain_interface::set_dirty_markets( const map<asset_id_type,asset_id_type>& d )
   {
      set_property( dirty_markets, fc::variant(d) );
   }

} } // bts::blockchain
<|endoftext|>


<commit_before>//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the XCore target.
//
//===----------------------------------------------------------------------===//

#include "XCore.h"
#include "XCoreTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
/// instructions for SelectionDAG operations.
///
namespace {
  class XCoreDAGToDAGISel : public SelectionDAGISel {
    const XCoreSubtarget &Subtarget;

  public:
    XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
      : SelectionDAGISel(TM, OptLevel),
        Subtarget(*TM.getSubtargetImpl()) { }

    SDNode *Select(SDNode *N) override;
    SDNode *SelectBRIND(SDNode *N);

    /// getI32Imm - Return a target constant with the specified value, of type
    /// i32.
    inline SDValue getI32Imm(unsigned Imm) {
      return CurDAG->getTargetConstant(Imm, MVT::i32);
    }

    inline bool immMskBitp(SDNode *inN) const {
      ConstantSDNode *N = cast<ConstantSDNode>(inN);
      uint32_t value = (uint32_t)N->getZExtValue();
      if (!isMask_32(value)) {
        return false;
      }
      int msksize = 32 - countLeadingZeros(value);
      return (msksize >= 1 && msksize <= 8) ||
              msksize == 16 || msksize == 24 || msksize == 32;
    }

    // Complex Pattern Selectors.
    bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);

    bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
                                      std::vector<SDValue> &OutOps) override;

    const char *getPassName() const override {
      return "XCore DAG->DAG Pattern Instruction Selection";
    }

    // Include the pieces autogenerated from the target description.
  #include "XCoreGenDAGISel.inc"
  };
}  // end anonymous namespace

/// createXCoreISelDag - This pass converts a legalized DAG into a
/// XCore-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
                                       CodeGenOpt::Level OptLevel) {
  return new XCoreDAGToDAGISel(TM, OptLevel);
}

bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
                                       SDValue &Offset) {
  FrameIndexSDNode *FIN = nullptr;
  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
    Offset = CurDAG->getTargetConstant(0, MVT::i32);
    return true;
  }
  if (Addr.getOpcode() == ISD::ADD) {
    ConstantSDNode *CN = nullptr;
    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
      // Constant positive word offset from frame index
      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
      return true;
    }
  }
  return false;
}

bool XCoreDAGToDAGISel::
SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
                             std::vector<SDValue> &OutOps) {
  SDValue Reg;
  switch (ConstraintCode) {
  default: return true;
  case 'm': // Memory.
    switch (Op.getOpcode()) {
    default: return true;
    case XCoreISD::CPRelativeWrapper:
      Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
      break;
    case XCoreISD::DPRelativeWrapper:
      Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
      break;
    }
  }
  OutOps.push_back(Reg);
  OutOps.push_back(Op.getOperand(0));
  return false;
}

SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
  SDLoc dl(N);
  switch (N->getOpcode()) {
  default: break;
  case ISD::Constant: {
    uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
    if (immMskBitp(N)) {
      // Transformation function: get the size of a mask
      // Look for the first non-zero bit
      SDValue MskSize = getI32Imm(32 - countLeadingZeros((uint32_t)Val));
      return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
                                    MVT::i32, MskSize);
    }
    else if (!isUInt<16>(Val)) {
      SDValue CPIdx =
        CurDAG->getTargetConstantPool(ConstantInt::get(
                              Type::getInt32Ty(*CurDAG->getContext()), Val),
                                      getTargetLowering()->getPointerTy());
      SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
                                            MVT::Other, CPIdx,
                                            CurDAG->getEntryNode());
      MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
      MemOp[0] = MF->getMachineMemOperand(
        MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
      cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
      return node;
    }
    break;
  }
  case XCoreISD::LADD: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                        N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::LSUB: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                        N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::MACCU: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::MACCS: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::LMUL: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::CRC8: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case ISD::BRIND:
    if (SDNode *ResNode = SelectBRIND(N))
      return ResNode;
    break;
  // Other cases are autogenerated.
  }
  return SelectCode(N);
}

/// Given a chain return a new chain where any appearance of Old is replaced
/// by New. There must be at most one instruction between Old and Chain and
/// this instruction must be a TokenFactor. Returns an empty SDValue if
/// these conditions don't hold.
static SDValue
replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
{
  if (Chain == Old)
    return New;
  if (Chain->getOpcode() != ISD::TokenFactor)
    return SDValue();
  SmallVector<SDValue, 8> Ops;
  bool found = false;
  for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    if (Chain->getOperand(i) == Old) {
      Ops.push_back(New);
      found = true;
    } else {
      Ops.push_back(Chain->getOperand(i));
    }
  }
  if (!found)
    return SDValue();
  return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
}

SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
  SDLoc dl(N);
  // (brind (int_xcore_checkevent (addr)))
  SDValue Chain = N->getOperand(0);
  SDValue Addr = N->getOperand(1);
  if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    return nullptr;
  unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
  if (IntNo != Intrinsic::xcore_checkevent)
    return nullptr;
  SDValue nextAddr = Addr->getOperand(2);
  SDValue CheckEventChainOut(Addr.getNode(), 1);
  if (!CheckEventChainOut.use_empty()) {
    // If the chain out of the checkevent intrinsic is an operand of the
    // indirect branch or used in a TokenFactor which is the operand of the
    // indirect branch then build a new chain which uses the chain coming into
    // the checkevent intrinsic instead.
    SDValue CheckEventChainIn = Addr->getOperand(0);
    SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
                                      CheckEventChainIn);
    if (!NewChain.getNode())
      return nullptr;
    Chain = NewChain;
  }
  // Enable events on the thread using setsr 1 and then disable them immediately
  // after with clrsr 1. If any resources owned by the thread are ready an event
  // will be taken. If no resource is ready we branch to the address which was
  // the operand to the checkevent intrinsic.
  SDValue constOne = getI32Imm(1);
  SDValue Glue =
    SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
                                   constOne, Chain), 0);
  Glue =
    SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
                                   constOne, Glue), 0);
  if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
      nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
                                nextAddr->getOperand(0), Glue);
  }
  return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
}
<commit_msg>Remove unused class variable.<commit_after>//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the XCore target.
//
//===----------------------------------------------------------------------===//

#include "XCore.h"
#include "XCoreTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
/// instructions for SelectionDAG operations.
///
namespace {
  class XCoreDAGToDAGISel : public SelectionDAGISel {

  public:
    XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
      : SelectionDAGISel(TM, OptLevel) {}

    SDNode *Select(SDNode *N) override;
    SDNode *SelectBRIND(SDNode *N);

    /// getI32Imm - Return a target constant with the specified value, of type
    /// i32.
    inline SDValue getI32Imm(unsigned Imm) {
      return CurDAG->getTargetConstant(Imm, MVT::i32);
    }

    inline bool immMskBitp(SDNode *inN) const {
      ConstantSDNode *N = cast<ConstantSDNode>(inN);
      uint32_t value = (uint32_t)N->getZExtValue();
      if (!isMask_32(value)) {
        return false;
      }
      int msksize = 32 - countLeadingZeros(value);
      return (msksize >= 1 && msksize <= 8) ||
              msksize == 16 || msksize == 24 || msksize == 32;
    }

    // Complex Pattern Selectors.
    bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);

    bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
                                      std::vector<SDValue> &OutOps) override;

    const char *getPassName() const override {
      return "XCore DAG->DAG Pattern Instruction Selection";
    }

    // Include the pieces autogenerated from the target description.
  #include "XCoreGenDAGISel.inc"
  };
}  // end anonymous namespace

/// createXCoreISelDag - This pass converts a legalized DAG into a
/// XCore-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
                                       CodeGenOpt::Level OptLevel) {
  return new XCoreDAGToDAGISel(TM, OptLevel);
}

bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
                                       SDValue &Offset) {
  FrameIndexSDNode *FIN = nullptr;
  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
    Offset = CurDAG->getTargetConstant(0, MVT::i32);
    return true;
  }
  if (Addr.getOpcode() == ISD::ADD) {
    ConstantSDNode *CN = nullptr;
    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
      // Constant positive word offset from frame index
      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
      return true;
    }
  }
  return false;
}

bool XCoreDAGToDAGISel::
SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
                             std::vector<SDValue> &OutOps) {
  SDValue Reg;
  switch (ConstraintCode) {
  default: return true;
  case 'm': // Memory.
    switch (Op.getOpcode()) {
    default: return true;
    case XCoreISD::CPRelativeWrapper:
      Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
      break;
    case XCoreISD::DPRelativeWrapper:
      Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
      break;
    }
  }
  OutOps.push_back(Reg);
  OutOps.push_back(Op.getOperand(0));
  return false;
}

SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
  SDLoc dl(N);
  switch (N->getOpcode()) {
  default: break;
  case ISD::Constant: {
    uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
    if (immMskBitp(N)) {
      // Transformation function: get the size of a mask
      // Look for the first non-zero bit
      SDValue MskSize = getI32Imm(32 - countLeadingZeros((uint32_t)Val));
      return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
                                    MVT::i32, MskSize);
    }
    else if (!isUInt<16>(Val)) {
      SDValue CPIdx =
        CurDAG->getTargetConstantPool(ConstantInt::get(
                              Type::getInt32Ty(*CurDAG->getContext()), Val),
                                      getTargetLowering()->getPointerTy());
      SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
                                            MVT::Other, CPIdx,
                                            CurDAG->getEntryNode());
      MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
      MemOp[0] = MF->getMachineMemOperand(
        MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
      cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
      return node;
    }
    break;
  }
  case XCoreISD::LADD: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                        N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::LSUB: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                        N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::MACCU: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::MACCS: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::LMUL: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
                      N->getOperand(2), N->getOperand(3) };
    return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case XCoreISD::CRC8: {
    SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
    return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
                                  Ops);
  }
  case ISD::BRIND:
    if (SDNode *ResNode = SelectBRIND(N))
      return ResNode;
    break;
  // Other cases are autogenerated.
  }
  return SelectCode(N);
}

/// Given a chain return a new chain where any appearance of Old is replaced
/// by New. There must be at most one instruction between Old and Chain and
/// this instruction must be a TokenFactor. Returns an empty SDValue if
/// these conditions don't hold.
static SDValue
replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
{
  if (Chain == Old)
    return New;
  if (Chain->getOpcode() != ISD::TokenFactor)
    return SDValue();
  SmallVector<SDValue, 8> Ops;
  bool found = false;
  for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    if (Chain->getOperand(i) == Old) {
      Ops.push_back(New);
      found = true;
    } else {
      Ops.push_back(Chain->getOperand(i));
    }
  }
  if (!found)
    return SDValue();
  return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
}

SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
  SDLoc dl(N);
  // (brind (int_xcore_checkevent (addr)))
  SDValue Chain = N->getOperand(0);
  SDValue Addr = N->getOperand(1);
  if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    return nullptr;
  unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
  if (IntNo != Intrinsic::xcore_checkevent)
    return nullptr;
  SDValue nextAddr = Addr->getOperand(2);
  SDValue CheckEventChainOut(Addr.getNode(), 1);
  if (!CheckEventChainOut.use_empty()) {
    // If the chain out of the checkevent intrinsic is an operand of the
    // indirect branch or used in a TokenFactor which is the operand of the
    // indirect branch then build a new chain which uses the chain coming into
    // the checkevent intrinsic instead.
    SDValue CheckEventChainIn = Addr->getOperand(0);
    SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
                                      CheckEventChainIn);
    if (!NewChain.getNode())
      return nullptr;
    Chain = NewChain;
  }
  // Enable events on the thread using setsr 1 and then disable them immediately
  // after with clrsr 1. If any resources owned by the thread are ready an event
  // will be taken. If no resource is ready we branch to the address which was
  // the operand to the checkevent intrinsic.
  SDValue constOne = getI32Imm(1);
  SDValue Glue =
    SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
                                   constOne, Chain), 0);
  Glue =
    SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
                                   constOne, Glue), 0);
  if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
      nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
                                nextAddr->getOperand(0), Glue);
  }
  return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
}
<|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.
 */
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <fc/smart_ref_impl.hpp>
#include <algorithm>

namespace graphene { namespace chain {

digest_type processed_transaction::merkle_digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::sig_digest( const chain_id_type& chain_id )const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return enc.result();
}

void transaction::validate() const
{
   FC_ASSERT( operations.size() > 0, "A transaction must have at least one operation", ("trx",*this) );
   for( const auto& op : operations )
      operation_validate(op);
}

graphene::chain::transaction_id_type graphene::chain::transaction::id() const
{
   auto h = digest();
   transaction_id_type result;
   memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h)));
   return result;
}

const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)
{
   digest_type h = sig_digest( chain_id );
   signatures.push_back(key.sign_compact(h));
   return signatures.back();
}

signature_type graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return key.sign_compact(enc.result());
}

void transaction::set_expiration( fc::time_point_sec expiration_time )
{
    expiration = expiration_time;
}

void transaction::set_reference_block( const block_id_type& reference_block )
{
   ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
   ref_block_prefix = reference_block._hash[1];
}

void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
{
   for( const auto& op : operations )
      operation_get_required_authorities( op, active, owner, other );
}

struct sign_state
{
      /** returns true if we have a signature for this key or can
       * produce a signature for this key, else returns false.
       */
      bool signed_by( const public_key_type& k )
      {
         auto itr = provided_signatures.find(k);
         if( itr == provided_signatures.end() )
         {
            auto pk = available_keys.find(k);
            if( pk  != available_keys.end() )
               return provided_signatures[k] = true;
            return false;
         }
         return itr->second = true;
      }

      optional<map<address,public_key_type>> available_address_sigs;
      optional<map<address,public_key_type>> provided_address_sigs;

      bool signed_by( const address& a ) {
         if( !available_address_sigs ) {
            available_address_sigs = std::map<address,public_key_type>();
            provided_address_sigs = std::map<address,public_key_type>();
            for( auto& item : available_keys ) {
             (*available_address_sigs)[ address(pts_address(item, false, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, false, 0) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 0) ) ] = item;
             (*available_address_sigs)[ address(item) ] = item;
            }
            for( auto& item : provided_signatures ) {
             (*provided_address_sigs)[ address(pts_address(item.first, false, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, false, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(item.first) ] = item.first;
            }
         }
         auto itr = provided_address_sigs->find(a);
         if( itr == provided_address_sigs->end() )
         {
            auto aitr = available_address_sigs->find(a);
            if( aitr != available_address_sigs->end() ) {
               auto pk = available_keys.find(aitr->second);
               if( pk != available_keys.end() )
                  return provided_signatures[aitr->second] = true;
               return false;
            }
         }
         return provided_signatures[itr->second] = true;
      }

      bool check_authority( account_id_type id )
      {
         if( approved_by.find(id) != approved_by.end() ) return true;
         return check_authority( get_active(id) );
      }

      /**
       *  Checks to see if we have signatures of the active authorites of
       *  the accounts specified in authority or the keys specified.
       */
      bool check_authority( const authority* au, uint32_t depth = 0 )
      {
         if( au == nullptr ) return false;
         const authority& auth = *au;

         uint32_t total_weight = 0;
         for( const auto& k : auth.key_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& k : auth.address_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& a : auth.account_auths )
         {
            if( approved_by.find(a.first) == approved_by.end() )
            {
               if( depth == max_recursion )
                  continue;
               if( check_authority( get_active( a.first ), depth+1 ) )
               {
                  approved_by.insert( a.first );
                  total_weight += a.second;
                  if( total_weight >= auth.weight_threshold )
                     return true;
               }
            }
            else
            {
               total_weight += a.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }
         }
         return total_weight >= auth.weight_threshold;
      }

      bool remove_unused_signatures()
      {
         vector<public_key_type> remove_sigs;
         for( const auto& sig : provided_signatures )
            if( !sig.second ) remove_sigs.push_back( sig.first );

         for( auto& sig : remove_sigs )
            provided_signatures.erase(sig);

         return remove_sigs.size() != 0;
      }

      sign_state( const flat_set<public_key_type>& sigs,
                  const std::function<const authority*(account_id_type)>& a,
                  const flat_set<public_key_type>& keys = flat_set<public_key_type>() )
      :get_active(a),available_keys(keys)
      {
         for( const auto& key : sigs )
            provided_signatures[ key ] = false;
         approved_by.insert( GRAPHENE_TEMP_ACCOUNT  );
      }

      const std::function<const authority*(account_id_type)>& get_active;
      const flat_set<public_key_type>&                        available_keys;

      flat_map<public_key_type,bool>   provided_signatures;
      flat_set<account_id_type>        approved_by;
      uint32_t                         max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH;
};

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,
                       uint32_t max_recursion_depth,
                       bool  allow_committe,
                       const flat_set<account_id_type>& active_aprovals,
                       const flat_set<account_id_type>& owner_approvals )
{ try {
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;

   for( const auto& op : ops )
      operation_get_required_authorities( op, required_active, required_owner, other );

   if( !allow_committe )
      GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
                       invalid_committee_approval, "Committee account may only propose transactions" );

   sign_state s(sigs,get_active);
   s.max_recursion = max_recursion_depth;
   for( auto& id : active_aprovals )
      s.approved_by.insert( id );
   for( auto& id : owner_approvals )
      s.approved_by.insert( id );

   for( const auto& auth : other )
   {
      GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
   }

   // fetch all of the top level authorities
   for( auto id : required_active )
   {
      GRAPHENE_ASSERT( s.check_authority(id) ||
                       s.check_authority(get_owner(id)),
                       tx_missing_active_auth, "Missing Active Authority ${id}", ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
   }

   for( auto id : required_owner )
   {
      GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
                       s.check_authority(get_owner(id)),
                       tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
   }

   GRAPHENE_ASSERT(
      !s.remove_unused_signatures(),
      tx_irrelevant_sig,
      "Unnecessary signature(s) detected"
      );
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
   auto d = sig_digest( chain_id );
   flat_set<public_key_type> result;
   for( const auto&  sig : signatures )
   {
      GRAPHENE_ASSERT(
         result.insert( fc::ecc::public_key(sig,d) ).second,
         tx_duplicate_sig,
         "Duplicate Signature detected" );
   }
   return result;
} FC_CAPTURE_AND_RETHROW() }

set<public_key_type> signed_transaction::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,
   uint32_t max_recursion_depth )const
{
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;
   get_required_authorities( required_active, required_owner, other );

   sign_state s(get_signature_keys( chain_id ),get_active,available_keys);
   s.max_recursion = max_recursion_depth;

   for( const auto& auth : other )
      s.check_authority(&auth);
   for( auto& owner : required_owner )
      s.check_authority( get_owner( owner ) );
   for( auto& active : required_active )
      s.check_authority( active ) || s.check_authority( get_owner( active ) );

   s.remove_unused_signatures();

   set<public_key_type> result;

   for( auto& provided_sig : s.provided_signatures )
      if( available_keys.find( provided_sig.first ) != available_keys.end() )
         result.insert( provided_sig.first );

   return result;
}

set<public_key_type> signed_transaction::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,
   uint32_t max_recursion
   ) const
{
   set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion );
   flat_set< public_key_type > result( s.begin(), s.end() );

   for( const public_key_type& k : s )
   {
      result.erase( k );
      try
      {
         graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
         continue;  // element stays erased if verify_authority is ok
      }
      catch( const tx_missing_owner_auth& e ) {}
      catch( const tx_missing_active_auth& e ) {}
      catch( const tx_missing_other_auth& e ) {}
      result.insert( k );
   }
   return set<public_key_type>( result.begin(), result.end() );
}

void signed_transaction::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,
   uint32_t max_recursion )const
{ try {
   graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
} FC_CAPTURE_AND_RETHROW( (*this) ) }

} } // graphene::chain
<commit_msg>get_required_authorities: active -= owner. #197<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.
 */
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <fc/smart_ref_impl.hpp>
#include <algorithm>

namespace graphene { namespace chain {

digest_type processed_transaction::merkle_digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::sig_digest( const chain_id_type& chain_id )const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return enc.result();
}

void transaction::validate() const
{
   FC_ASSERT( operations.size() > 0, "A transaction must have at least one operation", ("trx",*this) );
   for( const auto& op : operations )
      operation_validate(op);
}

graphene::chain::transaction_id_type graphene::chain::transaction::id() const
{
   auto h = digest();
   transaction_id_type result;
   memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h)));
   return result;
}

const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)
{
   digest_type h = sig_digest( chain_id );
   signatures.push_back(key.sign_compact(h));
   return signatures.back();
}

signature_type graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return key.sign_compact(enc.result());
}

void transaction::set_expiration( fc::time_point_sec expiration_time )
{
    expiration = expiration_time;
}

void transaction::set_reference_block( const block_id_type& reference_block )
{
   ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
   ref_block_prefix = reference_block._hash[1];
}

void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
{
   for( const auto& op : operations )
      operation_get_required_authorities( op, active, owner, other );
   for( const auto& account : owner )
      active.erase( account );
}

struct sign_state
{
      /** returns true if we have a signature for this key or can
       * produce a signature for this key, else returns false.
       */
      bool signed_by( const public_key_type& k )
      {
         auto itr = provided_signatures.find(k);
         if( itr == provided_signatures.end() )
         {
            auto pk = available_keys.find(k);
            if( pk  != available_keys.end() )
               return provided_signatures[k] = true;
            return false;
         }
         return itr->second = true;
      }

      optional<map<address,public_key_type>> available_address_sigs;
      optional<map<address,public_key_type>> provided_address_sigs;

      bool signed_by( const address& a ) {
         if( !available_address_sigs ) {
            available_address_sigs = std::map<address,public_key_type>();
            provided_address_sigs = std::map<address,public_key_type>();
            for( auto& item : available_keys ) {
             (*available_address_sigs)[ address(pts_address(item, false, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, false, 0) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 0) ) ] = item;
             (*available_address_sigs)[ address(item) ] = item;
            }
            for( auto& item : provided_signatures ) {
             (*provided_address_sigs)[ address(pts_address(item.first, false, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, false, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(item.first) ] = item.first;
            }
         }
         auto itr = provided_address_sigs->find(a);
         if( itr == provided_address_sigs->end() )
         {
            auto aitr = available_address_sigs->find(a);
            if( aitr != available_address_sigs->end() ) {
               auto pk = available_keys.find(aitr->second);
               if( pk != available_keys.end() )
                  return provided_signatures[aitr->second] = true;
               return false;
            }
         }
         return provided_signatures[itr->second] = true;
      }

      bool check_authority( account_id_type id )
      {
         if( approved_by.find(id) != approved_by.end() ) return true;
         return check_authority( get_active(id) );
      }

      /**
       *  Checks to see if we have signatures of the active authorites of
       *  the accounts specified in authority or the keys specified.
       */
      bool check_authority( const authority* au, uint32_t depth = 0 )
      {
         if( au == nullptr ) return false;
         const authority& auth = *au;

         uint32_t total_weight = 0;
         for( const auto& k : auth.key_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& k : auth.address_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& a : auth.account_auths )
         {
            if( approved_by.find(a.first) == approved_by.end() )
            {
               if( depth == max_recursion )
                  continue;
               if( check_authority( get_active( a.first ), depth+1 ) )
               {
                  approved_by.insert( a.first );
                  total_weight += a.second;
                  if( total_weight >= auth.weight_threshold )
                     return true;
               }
            }
            else
            {
               total_weight += a.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }
         }
         return total_weight >= auth.weight_threshold;
      }

      bool remove_unused_signatures()
      {
         vector<public_key_type> remove_sigs;
         for( const auto& sig : provided_signatures )
            if( !sig.second ) remove_sigs.push_back( sig.first );

         for( auto& sig : remove_sigs )
            provided_signatures.erase(sig);

         return remove_sigs.size() != 0;
      }

      sign_state( const flat_set<public_key_type>& sigs,
                  const std::function<const authority*(account_id_type)>& a,
                  const flat_set<public_key_type>& keys = flat_set<public_key_type>() )
      :get_active(a),available_keys(keys)
      {
         for( const auto& key : sigs )
            provided_signatures[ key ] = false;
         approved_by.insert( GRAPHENE_TEMP_ACCOUNT  );
      }

      const std::function<const authority*(account_id_type)>& get_active;
      const flat_set<public_key_type>&                        available_keys;

      flat_map<public_key_type,bool>   provided_signatures;
      flat_set<account_id_type>        approved_by;
      uint32_t                         max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH;
};

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,
                       uint32_t max_recursion_depth,
                       bool  allow_committe,
                       const flat_set<account_id_type>& active_aprovals,
                       const flat_set<account_id_type>& owner_approvals )
{ try {
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;

   for( const auto& op : ops )
      operation_get_required_authorities( op, required_active, required_owner, other );

   if( !allow_committe )
      GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
                       invalid_committee_approval, "Committee account may only propose transactions" );

   sign_state s(sigs,get_active);
   s.max_recursion = max_recursion_depth;
   for( auto& id : active_aprovals )
      s.approved_by.insert( id );
   for( auto& id : owner_approvals )
      s.approved_by.insert( id );

   for( const auto& auth : other )
   {
      GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
   }

   // fetch all of the top level authorities
   for( auto id : required_active )
   {
      GRAPHENE_ASSERT( s.check_authority(id) ||
                       s.check_authority(get_owner(id)),
                       tx_missing_active_auth, "Missing Active Authority ${id}", ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
   }

   for( auto id : required_owner )
   {
      GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
                       s.check_authority(get_owner(id)),
                       tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
   }

   GRAPHENE_ASSERT(
      !s.remove_unused_signatures(),
      tx_irrelevant_sig,
      "Unnecessary signature(s) detected"
      );
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
   auto d = sig_digest( chain_id );
   flat_set<public_key_type> result;
   for( const auto&  sig : signatures )
   {
      GRAPHENE_ASSERT(
         result.insert( fc::ecc::public_key(sig,d) ).second,
         tx_duplicate_sig,
         "Duplicate Signature detected" );
   }
   return result;
} FC_CAPTURE_AND_RETHROW() }

set<public_key_type> signed_transaction::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,
   uint32_t max_recursion_depth )const
{
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;
   get_required_authorities( required_active, required_owner, other );

   sign_state s(get_signature_keys( chain_id ),get_active,available_keys);
   s.max_recursion = max_recursion_depth;

   for( const auto& auth : other )
      s.check_authority(&auth);
   for( auto& owner : required_owner )
      s.check_authority( get_owner( owner ) );
   for( auto& active : required_active )
      s.check_authority( active ) || s.check_authority( get_owner( active ) );

   s.remove_unused_signatures();

   set<public_key_type> result;

   for( auto& provided_sig : s.provided_signatures )
      if( available_keys.find( provided_sig.first ) != available_keys.end() )
         result.insert( provided_sig.first );

   return result;
}

set<public_key_type> signed_transaction::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,
   uint32_t max_recursion
   ) const
{
   set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion );
   flat_set< public_key_type > result( s.begin(), s.end() );

   for( const public_key_type& k : s )
   {
      result.erase( k );
      try
      {
         graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
         continue;  // element stays erased if verify_authority is ok
      }
      catch( const tx_missing_owner_auth& e ) {}
      catch( const tx_missing_active_auth& e ) {}
      catch( const tx_missing_other_auth& e ) {}
      result.insert( k );
   }
   return set<public_key_type>( result.begin(), result.end() );
}

void signed_transaction::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,
   uint32_t max_recursion )const
{ try {
   graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
} FC_CAPTURE_AND_RETHROW( (*this) ) }

} } // graphene::chain
<|endoftext|>