Что означает функция «вызов» Solidity?

address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName"); //1
nameReg.call(bytes4(sha3("fun(uint256)")), a); //2
if(!nameReg.call.value(10)){throw;} //3

Здесь говорится,

Кроме того, для взаимодействия с контрактами, которые не соответствуют ABI, предоставляется вызов функции, который принимает произвольное количество аргументов любого типа. Эти аргументы дополняются до 32 байтов и объединяются. Единственным исключением является случай, когда первый аргумент закодирован ровно в четыре байта. В этом случае он не дополняется, чтобы разрешить использование здесь сигнатур функций.

  • Законны ли 1 и 2?
  • Означает ли это, что 2 является незаконным?
  • Что означает 3?

Ответы (1)

Solidity call— это низкоуровневый интерфейс для отправки сообщения контракту. Он возвращается false, если подвызов встречает исключение, в противном случае он возвращает true. Не существует понятия законного вызова, если он компилируется, это действительный Solidity.

  1. nameReg.call("register", "MyName")это сообщение, которое передает определенные байты в nameReg. Для байтов см.: Понимание вызова стиля nameReg.call("register", "MyName") между контрактами.

  2. nameReg.call(bytes4(sha3("fun(uint256)")), a)— это сообщение, которое вызовет функцию с именем fun(если nameReg соответствует ABI) и передаст ей необработанные данные без дополнений a(вам нужно aсначала правильно заполнить до 32 байтов, если вы хотите, чтобы поведение соответствовало ABI ) . Для uint256использования левого заполнения. ).

Для 3 contract.call.value(...)(...)это способ добавить эфир при вызове контракта. if(!nameReg.call.value(10)()){throw;}является примером обработки случая сбоя подвызова. Обратите внимание на дополнительные круглые скобки value(10)(), которые вызывают резервную функцию.

callявляется низкоуровневым интерфейсом, и проще вызвать функцию напрямую, nameReg.fun(a)чем во втором примере. Прямой вызов также является типобезопасным и позволяет использовать возвращаемое значение fun.

Обратите внимание, что в случае 1 "register"и "MyName"дополняются до 32 байтов, тогда как в случае 2 aобъединяются непосредственно с 4-байтовымbytes4(sha3("fun(uint256)"))
@eth, так ты имеешь в виду, что он игнорирует возвращаемое значение по контракту?
@user2284570 user2284570 Да, Solidity callне возвращает возвращаемое значение контрактной функции: он возвращает только то, столкнулось ли функция с исключением или нет.
Насколько я понимаю, (bool success, bool returnBytes) = addr.call{...}(abi.encodeWithSignature(...), ...)это новый рекомендуемый способ (1) вызова функций без броска, если функция не может быть вызвана, и (2) отправки платежа оплачиваемым функциям. Так что я почти уверен, что комментарий Крисета относится callтолько к более старым версиям.
@LukeHutchison Думаю, вы правы, проголосовали и удалили комментарий chriseth. Не уверен, насколько сильно редактировать остальную часть этого ответа; не стесняйтесь писать второй ответ, который гораздо более актуален :)