Если оператор в цикле for не отфильтровывает элементы в браке - PullRequest
0 голосов
/ 04 июля 2018
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// @return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
    uint [] results;
    for(uint i = 0 ; i<homes.length; i++) {
        if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
            results.push(homes[i].id);
        }
    }
    return results;    
}

Предполагается, что результатом будет список идентификаторов, которые соответствуют введенному физическому адресу, однако он не фильтрует, а возвращает все доступные дома. Когда я переключаюсь на использование String, ничего не меняется.

Вот весь код:

pragma solidity ^0.4.0;

import "browser/StringUtils.sol";

// @title HomeListing

contract HomeListing {

    struct Home {
        uint id;
        string physicalAddress;
        bool available;
    }

    Home[] public homes;
    mapping (address => Home) hostToHome;
    event HomeEvent(uint _id);
    event Test(uint length);

    constructor() {

    }

    // @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
    function addHome(string _physicalAddress) public {
        uint _id = uint(keccak256(_physicalAddress, msg.sender));
        homes.push(Home(_id, _physicalAddress, true));
    }

    // @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
    // @return _id - list of ids for homes
    function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
        uint [] results;
        for(uint i = 0 ; i<homes.length; i++) {
            string location = homes[i].physicalAddress;
            if(StringUtils.equal(location,_physicalAddress )) {
                results.push(homes[i].id);
            }
        }
        return results;
    }
}

1 Ответ

0 голосов
/ 04 июля 2018

Часть, доставляющая вам неприятности - это строка uint[] results;. Массивы, объявленные как локальные переменные, по умолчанию ссылаются на storage память. Из раздела «Что такое ключевое слово в памяти» в Документация по твердости :

Существуют значения по умолчанию для места хранения в зависимости от того, к какому типу переменных это относится:

  • переменные состояния всегда находятся в хранилище
  • Аргументы функции находятся в памяти по умолчанию
  • локальные переменные хранилища ссылок структуры, массива или типа отображения по умолчанию
  • локальные переменные типа значения (т. Е. Ни массив, ни структура, ни отображение) не сохраняются в стеке

В результате вы ссылаетесь на первый слот хранения вашего контракта, который, как оказалось, Home[] public homes. Вот почему вы получаете весь массив обратно.

Чтобы решить проблему, вам нужно использовать массив memory. Однако у вас есть дополнительная проблема в том, что вы не можете использовать динамические массивы памяти в Solidity. Обходной путь - выбрать ограничение размера результата и объявить массив статически.

Пример (ограничено 10 результатами):

function listHomesByAddress(string _physicalAddress) public view returns(uint[10]) {
    uint [10] memory results;
    uint j = 0;
    for(uint i = 0 ; i<homes.length && j < 10; i++) {
        if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
            results[j++] = homes[i].id;
        }
    }
    return results;

} 
...