У меня есть смарт-контракт с некоторыми участниками, который должен изменяться при определенных событиях. Для простоты представим, что у нас есть контракт приветствующего.
Если я вызываю 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?
Поскольку ваша 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);
}
);
)
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});
То есть, поскольку они могут изменять состояние, они должны получать оплату за газ, чтобы выполнить работу.
Чтобы ответить на оставшийся вопрос, контракт не может оплачивать собственный газ , как это можно представить в этом примере, поэтому финансирование его с помощью эфира не помогает.
hcvst
q9f