Являются ли подчеркивания `_` в коде модификаторов или они просто предназначены для того, чтобы выглядеть круто?

Я часто вижу _ в модификаторах

modifier onlyOwner() {
    if (msg.sender != owner) throw;
    _
}

Выполняет ли он какой-либо код или он предназначен для упрощения чтения кода?

34 голоса | спросил dor 10 J0000006Europe/Moscow 2016, 07:36:52

1 ответ


35

Обновление от 12 октября 2016 г.

От Solidity версии 0.4.0+ вам нужно добавить точку с запятой после _. См. Solidity - версия 0.4.0 :

  
  • Измените _ на _; в модификаторах.
  •   

Нижеприведенные тесты работают только в Solidity <v 0.4.0.



Резюме

  • Код для изменяемой функции вставляется, когда в модификаторе помещается _.
  • Вы можете добавить несколько кодов _ s в код модификатора. И код изменяемой функции вставлен в каждое место, где _ находится в модификаторе. См. modifier checkThree. Это может быть предотвращено более поздними версиями компилятора solc.
  • Модификаторы вызываются в последовательности, в которой они были определены (checkOne checkTwo checkThree), и в конце функции они вызываются в обратном порядке. Модификаторы, похоже, применяются как стек. В этом примере все равно.



Подробнее

Из Функции твердости - модификаторы функций :

  

Модификаторы PT могут использоваться для легкого изменения поведения функций, например, для автоматической проверки состояния перед выполнением функции. Они являются наследуемыми свойствами контрактов и могут быть переопределены производными контрактами.

contract owned {
  function owned() { owner = msg.sender; }
  address owner;

  // This contract only defines a modifier but does not use it - it will
  // be used in derived contracts.
  // The function body is inserted where the special symbol "_" in the
  // definition of a modifier appears.
  modifier onlyowner { if (msg.sender == owner) _ }
}


Вот пример из EtherScan.io - DAO - Исходный код .

Модификатор onlyTokenholders ограничивает «измененные» функции от выполнения сторонними владельцами.

modifier onlyTokenholders {
    if (balanceOf(msg.sender) == 0) throw;
        _
}

Вот функция vote(...) с модификатором onlyTokenHolders:

function vote(
    uint _proposalID,
    bool _supportsProposal
) onlyTokenholders noEther returns (uint _voteID) {

    Proposal p = proposals[_proposalID];
    if (p.votedYes[msg.sender]
        || p.votedNo[msg.sender]
        || now >= p.votingDeadline) {

        throw;
    }

Код в функции vote(...) выполняется только в том случае, если проверка модификатора не выдает ошибку из выражения if (balanceOf(msg.sender) == 0) throw;. _ представляет собой тело функции vote(...).


Из Изучите X в Y минутах - Где X = Солидность , вот пример, где _ не находится в конце функции модификатора:

_


Возьмем '_' для тестового прогона

Вот код для тестирования // underscore can be included before end of body, // but explicitly returning will skip, so use carefully modifier checkValue(uint amount) { _ if (msg.value > amount) { msg.sender.send(amount - msg.value); } } :

_

Сжат код

contract TestModifier {

    string[] public messages;
    uint256 testVariable;

    function numberOfMessages() constant returns (uint256) {
        return messages.length;
    }

    modifier checkOne {
        messages.push("checkOne - 1");
        if (testVariable == 123) 
            throw;
        _
        messages.push("checkOne - 2");
        if (testVariable == 123) 
            throw;
    }

    modifier checkTwo {
        messages.push("checkTwo - 1");
        if (testVariable == 123) 
            throw;
        _
        messages.push("checkTwo - 2");
        if (testVariable == 123) 
            throw;
    }

    modifier checkThree {
        messages.push("checkThree - 1");
        if (testVariable == 123) 
            throw;
        _
        messages.push("checkThree - 2");
        if (testVariable == 123) 
            throw;
        _
        messages.push("checkThree - 3");
        if (testVariable == 123) 
            throw;
    }

    function test() checkOne checkTwo checkThree returns (uint256) {
        messages.push("test - 1");
        testVariable = 345;
        messages.push("test - 2");
        return testVariable;
    }
}

Вставлен контракт в цепочку:

> var testModifierSource='contract TestModifier { string[] public messages; uint256 testVariable; function numberOfMessages() constant returns (uint256) { return messages.length; } modifier checkOne { messages.push("checkOne - 1"); if (testVariable == 123)  throw; _ messages.push("checkOne - 2"); if (testVariable == 123)  throw; } modifier checkTwo { messages.push("checkTwo - 1"); if (testVariable == 123)  throw; _ messages.push("checkTwo - 2"); if (testVariable == 123)  throw; } modifier checkThree { messages.push("checkThree - 1"); if (testVariable == 123)  throw; _ messages.push("checkThree - 2"); if (testVariable == 123)  throw; _ messages.push("checkThree - 3"); if (testVariable == 123)  throw; } function test() checkOne checkTwo checkThree returns (uint256) { messages.push("test - 1"); testVariable = 345; messages.push("test - 2"); return testVariable; }}'
undefined

Отправлена ​​транзакция для вызова функции > var testModifierCompiled = web3.eth.compile.solidity(testModifierSource); undefined > var testModifierContract = web3.eth.contract(testModifierCompiled.TestModifier.info.abiDefinition); var testModifier = testModifierContract.new({ from:web3.eth.accounts[0], data: testModifierCompiled.TestModifier.code, gas: 1000000}, function(e, contract) { if (!e) { if (!contract.address) { console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); } else { console.log("Contract mined! Address: " + contract.address); console.log(contract); } } }) ... Contract mined! Address: 0xd2ca2d34da6e50d28407f78ded3a07962b56181c [object Object] :

test()

Проверено результатов:

> testModifier.test(eth.accounts[0], {
  from:web3.eth.accounts[0], 
  data: testModifierCompiled.TestModifier.code,
  gas: 1000000
});


Вывод утверждения возврата в > var i; > for (i = 0; i < testModifier.numberOfMessages(); i++) { console.log(testModifier.messages(i)); } checkOne - 1 checkTwo - 1 checkThree - 1 test - 1 test - 2 :

Я удалил оператор return, поэтому исходный код для test():

test

И повторный запуск теста для получения следующих результатов:

function test() checkOne checkTwo checkThree returns (uint256) {
    messages.push("test - 1");
    testVariable = 345;
    messages.push("test - 2");
    // return testVariable;
}
ответил The Officious BokkyPooBah 10 J0000006Europe/Moscow 2016, 08:01:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132