Как манипулировать данными в смарт-контракте Solidity?

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

Если я вызываю greeter.greet()консоль JavaScript, она отвечает чем-то вроде Hello World. Но что, если я хочу подсчитать количество приветствий и сохранить их внутри контракта?

Моя первая попытка была следующей:

contract greeter
{
  string greeting;
  uint calls;

  function greeter ( string _greeting ) public
  {
    greeting = _greeting;
    calls = 0;
  }

  function greet ( ) constant returns ( string )
  {
    calls = calls + 1; // does not work
    return greeting;
  }
}

Переменная call не была обновлена. Моя первая догадка заключается в том, что мне нужно как-то создать транзакцию для оплаты газа. Я использовал web3.jsдля развертывания контракта. Должен ли я использовать web3 также для вызова greet()с транзакцией?

Или я могу пополнить контрактный счет некоторым количеством эфира, чтобы контракт мог оплачивать свой собственный газ? Как манипулировать данными в смарт-контракте Solidity?

Я еще не смотрел на web3.js, но мне любопытно узнать, как вы, как вы написали, развернули с ним свой контракт. Не могли бы вы указать мне более подробную информацию?
@hcvst, вы можете следить за моими маленькими шагами по развертыванию с помощью web3js на github .

Ответы (2)

Поскольку ваша greet()функция помечена constant, web3 по умолчанию имитирует вызов и возвращает значение, но транзакция не отправляется, и поэтому никакие изменения состояния не сохраняются. Это поведение может быть принудительно реализовано в непостоянных методах с помощью contract.method.call().

Чтобы вызвать функцию таким образом, чтобы отправить транзакцию и обновить цепочку, используйте greeter.greet.sendTransaction({from:eth.coinbase, gas:100000}).

К сожалению, в то время как другие контракты получат правильное возвращаемое значение, web3 вернет хэш транзакции, а не возвращаемое значение. В этом случае имеет смысл использовать Events .

Например, твердость будет выглядеть примерно так:

contract greeter { 
    string greeting; 
    uint calls; 
    event Greet (string greeting);
    function greeter ( string _greeting ) public { 
        greeting = _greeting; 
        calls = 0; 
     }
     function greet ( ) public returns ( string ) { 
         calls = calls + 1; 
         Greet(greeting);
          return greeting; 
     } 
 }

И чтобы получить возвращаемое значение:

 greeter.greet.sendTransaction(
    {from:eth.coinbase, gas:100000},

    function (error, result){ 
    var event = greeter.Greet()
    event.watch(
        function(error, result){ 
             if (!error) console.log(result.args.greeting); 
         }
    );
)
Проголосовал, хорошая мысль о возвращаемом значении; отредактировал мой ответ, чтобы сослаться на ваш для web3js и событий, и кратко упомянул случай контракта на контракт.
Я думаю, вы хотите удалить «константу» в приветствии ()? Кроме того, "result.greeting" может быть неточным. IIRC может понадобиться что-то вроде «result.args.greeting».
@eth Спасибо, я совсем забыл о константе, и result.args.greetingэто правильно.

Проблема в том, что greetэто constantфункция , поэтому никакие изменения состояния не допускаются. Изменение значения чего-либо в хранилище будет изменением состояния.

Решение: удалить constant.

Да, вы должны использовать web3 sendTransaction, когда хотите изменить состояние. sendTransactionиспользуется по умолчанию для непостоянных функций, но не использовался, поскольку constantбыл указан. Обратите внимание, что возвращаемое значение будет доступно только из другого контракта — с транзакциями web3js для получения возвращаемого значения нужно будет использовать Events, как ответил Tjaden Hess .

Еще из FAQ :

В чем разница между функцией, помеченной как константа, и функцией, которая таковой не является?

constantфункции могут выполнять какое-то действие и возвращать значение, но не могут изменять состояние (это еще не обеспечивается компилятором). Другими словами, константная функция не может сохранять или обновлять какие-либо переменные в рамках контракта или более широкой цепочки блоков. Эти функции вызываются c.someFunction(...)из geth или любой другой среды web3.js.

«неконстантные» функции (те, у которых отсутствует спецификатор константы) должны вызываться с помощью c.someMethod.sendTransaction({from:eth.accounts[x], gas: 1000000});То есть, поскольку они могут изменять состояние, они должны получать оплату за газ, чтобы выполнить работу.


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