Могут ли контракты оплачивать газ вместо отправителя сообщения?

Можно ли договору оплатить расходы на газ (или его часть), которые являются результатом вызова контракта? Или отправитель сообщения всегда платит результирующие расходы на газ независимо от того, что?

60 голосов | спросил mKoeppelmann 21 Jam1000000amThu, 21 Jan 2016 02:57:28 +030016 2016, 02:57:28

7 ответов


30

В настоящее время пользователь, инициирующий транзакцию, должен уплатить сбор. Тем не менее, Serenity, скорее всего, позволит использовать схемы оплаты по контрактам. (См. Сообщение в блоге Vitalik здесь ). Возможная работа - это контракт, который возмещает отправителю, однако это все равно потребует от пользователя удерживать некоторый эфир и может позволить злонамеренным сторонам неоднократно называть контракт, чтобы истощить его средства.

ответил JackWinters 21 Jam1000000amThu, 21 Jan 2016 03:12:23 +030016 2016, 03:12:23
20

Нет, отправитель с нулевым эфиром не может «попросить» контракт оплатить расходы на газ. Отправитель с нулевым эфиром даже не может отправить транзакцию.

Подробнее: отправитель транзакции должен иметь достаточно газа для покрытия сделки. Этот газ требуется даже до того, как можно даже назвать контракт. Как только требования к газу удовлетворяются (чтобы транзакция выполнялась полностью без истечения срока действия газа), указанный контракт может отправить отправителю любые суммы средств, которые заключен в договоре: сетевое поведение заключается в том, что отправитель может получить больше эфира, чем они началось с, но это отличается от контракта, оплачивающего газ.

Как будто вы можете ездить в банк, чтобы получить деньги, но сначала вам нужно топливо, чтобы иметь возможность ездить в банк: банк не может отправить вам топливные деньги, прежде чем вы едете в банк.

Продолжается обсуждение здесь для будущей версии (Serenity), которая может изменить это поведение.


В Solidity есть синтаксис gas(), как указано ниже в одном из ответов:

contract Gracious {
  function runMe() {
    this.realWork.gas(1000000)();
  }
}

gas() не означает использование контрактного эфира для оплаты газа. gas() ограничивает количество газа, которое получает подканал (realWork). Если runMe предоставлено 3 000 000 газов, тогда realWork будет потреблять более 1 000 000 газов, поэтому любые функции, вызываемые при завершении runMe, будут гарантированно иметь 2 000 000 газа. Если realWork потребляет более 1 000 000 газов, тогда исключение будет генерироваться немедленно, все 3 000 000 газа будут выплачены шахтеру, а транзакция будет отменена.

ответил eth 21 Jam1000000amThu, 21 Jan 2016 03:11:13 +030016 2016, 03:11:13
6

Копирование моего андера отсюда Как заставить кого-то платить для газа?

Есть два обходных пути с их плюсами и минусами:

  1. Использовать сигнатуры

    • Каждая функция вашего смарт-контракта должна иметь параметр signature.
    • Люди, которые хотят взаимодействовать со смарт-контрактом, должны подписать параметры функции своим личным ключом своего аккаунта и отправить его владельцу смарт-контракта (через любой канал связи).
    • Затем владелец передает параметры вместе с подписью на блок-цепь, оплачивая газ. Подпись гарантирует, что сообщение было одобрено пользователем.
  2. Возврат использованного газа в конце транзакции. Модификатор можно использовать для этого (см. Ниже).

Ниже приведены дополнительные сведения для каждой опции:


Использование подписей

Вот простой договор ReceiverPays, который позволяет сделать получателю оплату за газ:

pragma solidity ^0.4.20;

contract ReceiverPays {
    address owner = msg.sender;

    mapping(uint256 => bool) usedNonces;

    // Funds are sent at deployment time.
    function ReceiverPays() public payable { }


    function claimPayment(uint256 amount, uint256 nonce, bytes sig) public {
        require(!usedNonces[nonce]);
        usedNonces[nonce] = true;

        // This recreates the message that was signed on the client.
        bytes32 message = prefixed(keccak256(msg.sender, amount, nonce, this));

        require(recoverSigner(message, sig) == owner);

        msg.sender.transfer(amount);
    }

    // Destroy contract and reclaim leftover funds.
    function kill() public {
        require(msg.sender == owner);
        selfdestruct(msg.sender);
    }


    // Signature methods

    function splitSignature(bytes sig)
        internal
        pure
        returns (uint8, bytes32, bytes32)
    {
        require(sig.length == 65);

        bytes32 r;
        bytes32 s;
        uint8 v;

        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }

        return (v, r, s);
    }

    function recoverSigner(bytes32 message, bytes sig)
        internal
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sig);

        return ecrecover(message, v, r, s);
    }

    // Builds a prefixed hash to mimic the behavior of eth_sign.
    function prefixed(bytes32 hash) internal pure returns (bytes32) {
        return keccak256("\x19Ethereum Signed Message:\n32", hash);
    }
}

Более подробную информацию можно найти в этой статье https://programtheblockchain.com/posts/2018/02/17/signing-and-verifying-messages-in-ethereum/

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


Возврат использованного газа отправителю транзакции

Это не идеальное решение, но вы можете вернуть стоимость газа отправителю транзакции. Вы можете сделать это с помощью модификатора:

pragma solidity^0.4.11;

contract SomeContract {

    event SomeEvent(address sender);

    // Need to allow depositing ether to the contract
    function() public payable {
    }

    modifier refundGasCost()
    {
        uint remainingGasStart = msg.gas;

        _;

        uint remainingGasEnd = msg.gas;
        uint usedGas = remainingGasStart - remainingGasEnd;
        // Add intrinsic gas and transfer gas. Need to account for gas stipend as well.
        usedGas += 21000 + 9700;
        // Possibly need to check max gasprice and usedGas here to limit possibility for abuse.
        uint gasCost = usedGas * tx.gasprice;
        // Refund gas cost
        tx.origin.transfer(gasCost);
    }

    function doSomething() external refundGasCost {
        SomeEvent(msg.sender);  
    }
}

Возврат таким образом подразумевает некоторые накладные расходы: по крайней мере 9700 газа необходимо заплатить дополнительно за вызов функции transfer внутри модификатора refundGasCost. Также в код refundGasCost следует добавить газ для других кодов операций в usedGas.


https://github.com/ethereum/wiki/wiki/Design-Rationale

  

Требование от отправителей транзакций платить за газ вместо контрактов существенно увеличивает удобство использования. Очень раноу версий Ethereum были контракты на оплату газа, но это привело к довольно уродливой проблеме, заключавшейся в том, что каждый контракт должен был реализовывать «защитный» код, который обеспечивал бы, чтобы каждое входящее сообщение компенсировало контракт достаточным количеством эфира, чтобы оплатить газ, который он потреблял.

...

  

ПРОИСХОЖДЕНИЕ: первичное использование кода операции ORIGIN, который предоставляет отправителю транзакции, заключается в том, чтобы разрешить контракты производить выплаты за газ.

ответил medvedev1088 11 MarpmSun, 11 Mar 2018 22:33:57 +03002018-03-11T22:33:57+03:0010 2018, 22:33:57
5

Не все звонки по контракту требуют газа. Это так называемый «сухой ход». https://github.com/ethereum/go -ethereum /вики /контракты-и-транзакций # взаимодействия-с-контрактов

  

Теперь все вызовы функций, указанные в abi, становятся доступными   экземпляр контракта. Вы можете просто вызвать эти методы в контракте   экземпляр и цепочка sendTransaction (3, {from: address}) или вызов (3) в   Это. Разница между ними заключается в том, что вызов выполняет «сухой ход»,   локально, на вашем компьютере, в то время как sendTransaction фактически отправит   ваша транзакция для включения в цепочку блоков и результаты   его исполнение в конечном итоге станет частью глобального консенсуса. В   другими словами, используйте вызов, если вас интересует только возвращаемое значение   и используйте sendTransaction, если вы только заботитесь о «побочных эффектах» на   состояние договора.

Таким образом, можно предоставить метод в контракте для пользователей для нулевого расхода газа - в приведенном выше примере это функция умножения.

ответил jgabios 26 Jpm1000000pmTue, 26 Jan 2016 16:21:45 +030016 2016, 16:21:45
1

Не сейчас, но в настоящее время обсуждается с EIP. Гэвин Вуд говорит, что есть способ сделать это сейчас, но из моего понимания это что-то вроде взлома.

ответил VoR0220 26 Jpm1000000pmTue, 26 Jan 2016 21:52:58 +030016 2016, 21:52:58
1

Во-первых, я хочу поблагодарить @eth и @ medvedev1088 за их ответы. @eth утверждает, что

  

Как будто вы можете ездить в банк, чтобы получить деньги, но сначала вам нужно топливо, чтобы иметь возможность ездить в банк: банк не может отправить вам топливные деньги, прежде чем вы едете в банк.

Я думаю, что каждый, кто работает с токенами утилиты, сталкивается с этой начальной проблемой. Я забочусь о разработчике, потому что он не является удобным для пользователей, которые покупают ethereum от бирж или местных жителей. Поэтому я ищу возможные решения, которые работают вокруг «первой проблемы с токеном». Ответ @ medvedev1088 выглядит как решение с первого взгляда. Я не понял, прежде чем тестировать его, но после теста, который я сделал, я могу легко сказать

  

Получатель заявляет о своей оплате, представляя подписанное сообщение на смарт-контракт. Интеллектуальный контракт проверяет его подлинность и затем освобождает средства.

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

Если у вас есть собственная частная сеть, вы можете протестировать ее с помощью кода ниже. (Перед его выполнением вам необходимо развернуть контракт как минимум 6 эфиров и развернуть его с учетной записи coinbase)

Код можно найти в этой скрипке

Надеюсь, я не понял неправильный подход @ medvedev1088.

ответил Mehmet Doğan 17 PMpTue, 17 Apr 2018 18:01:07 +030001Tuesday 2018, 18:01:07
0

Только что опубликовала небольшую библиотеку, чтобы добавить возможность делегировать создание транзакции (оплата сборов): https: //github .com /bitclave /Feeless

Вам нужно просто:

  1. Наследовать свой смарт-контракт из Feeless смарт-контракт
  2. Добавить модификатор feeless для любых методов, которые вы хотите косвенно коснуться
  3. Используйте msgSender вместо msg.sender в этих методах и методах, вызываемых ими внутренне

И кто-то сможет полностью заплатить гонорары за любого другого. Например, служба может оплачивать комиссионные за пользовательские транзакции и компенсировать эту плату собственными комиссионными за токены.

ответил k06a 24 PMpTue, 24 Apr 2018 16:54:34 +030054Tuesday 2018, 16:54:34

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

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

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