Solidity: Есть ли механизм захвата для броска? Если не переключиться на возврат, может быть лучше?

Судя по отзывам опытных наставников, здесьthrow предлагается механизм . Я предполагаю, что механизм перехвата не существует для : https://ethereum.stackexchange.com/a/2512/4575 .throw

Исходя из этого, у меня есть проблема: сначала я должен проверить некоторые условия, которые могут иметь высокое значение газа. Если условие не throwбудет выполнено. Поэтому, если условие не выполняется, я хочу вернуть деньги клиенту. В противном случае деньги должны возвращаться кластеру.

[В] Если условие не выполняется, throwпроизойдет. Поскольку throwзавершает код, у меня нет возможности поймать возвращенную версию и применить 1 строку кода для возврата денег клиенту. Есть ли альтернативное решение для решения этой проблемы?

Обратите внимание, что состояние изменится. Так что я должен сделать, throwесли есть условие не удается.

function payMeBack() {
    if(require(<some condition>)) //if condition is wrong throw take place and never JUMPS to else side.
       if(!client.send(gainedWei)) throw; 
    else
       if(!cluster.send(gainedWei)) throw; 
    gainedWei = 0;
    client.success = 1;
}

Спасибо за ваше драгоценное время и помощь.

Ответы (2)

Нет механизма захвата для броска. Состояние возвращается к состоянию до транзакции. Не обращайте внимания на порядок операций и даже операции, имевшие место в вызывающих контрактах. Throwозначает, что транзакция, исходящая от EOA, подписавшего транзакцию , не произошла (с некоторым побочным эффектом, что весь предоставленный газ был уничтожен).

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

Безопасная отправка:

  1. Сначала сделайте оптимистичный учет... убедитесь, что состояние завершено перед отправкой, потому что мы не можем делать никаких дальнейших предположений об управлении потоком после того, как пообщаемся с ненадежным контрактом.
  2. Попробуйте send()и проверьте результат.
  3. Отменить изменения (например, с помощью throw), если что-то пошло не так.

Выше у вас есть учет после отправки.

Ненадежные контракты

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

  1. Не говорите более чем с одним внешним контрактом одновременно. То есть два sends()в одной транзакции — это красный флаг. На мой вкус, это слишком занято.

Предложение: разбейте это на более мелкие функции и сосредоточьтесь на учете, а не сразу на send(). Следите за тем, кому что причитается, как к арифметическим операциям/операциям хранения. В этом случае вам не нужно throw, и if() {} else {}логика должна работать нормально.

Используйте шаблон вывода, чтобы иметь дело с одной претензией и одним пользователем за раз. https://github.com/ConsenSys/smart-contract-best-practices#favor-pull-over-push-for-external-calls

Надеюсь, поможет.

«непонятно, почему средства должны быть отправлены на один из возможных» Думайте, что это система наподобие Amazon. Когда мы pay()сначала покупаем товар, деньги будут списаны со счета клиента. В payMeBack() проверьте условие, например: успешно ли доставлен товар продавцу. Если да, то деньги, вырученные по контракту, будут выплачены продавцу seller.send(gainedWei). Если нет, он будет возвращен клиенту в качестве возмещения client.send(gainedWei). Надеюсь, стало немного понятнее. Таким образом, в основном payMeBack также должен решать, кто получит деньги, продавец или клиент, исходя из условий. @РобХитченс.
Я так понимаю вместо броска надо придумать какой-то механизм "возврата состояния"? Не должен ли требоваться дополнительный газовый механизм? @РобХитченс
Если вы не бросаете, то отмените все изменения состояния.
Мое ifусловие - это функция, и я изменю некоторые состояния, которые вернут true или false. Функция может потреблять много газа. Таким образом, может показаться, что это просто использование , поскольку throwвозврат if/elseсостояний вручную может потребовать дополнительного использования газа. @Роб Хитченс
В качестве общего эмпирического правила, по возможности, предпочитайте «Fail Hard», поскольку он возвращает все для вас (в отличие от «catch»). Вы можете думать о возможных ответах как «да», «нет» и «неприемлемо». Постарайтесь выставить свою «охрану впереди» и не меняйте ситуацию, если проблема заключается в том, чтобы ее распутать. Вы описываете какой-то частичный успех, который вам, вероятно, следует логически разбить - либо полный провал, либо полный успех.
Нелогично, но я просто добавляю некоторые узлы в связанный список, поэтому для возврата мне нужно их удалить. PS: Конечно, я забыл принять, прежде чем сожалеть об этом.

В дополнение к комментариям Роба, некоторые комментарии к используемому шаблону. <some condition>не нужно бросать так не нужно require. Просто используйте if(<some condition>)и полагайтесь на успех/бросок условных .send()'s.

Кроме того, the if(!<condition>)throwможно заменить на require(<condition>)as it throws false(но обратите внимание на обратную условную логику).

function payMeBack() {
    if(<some condition>)
        require(client.send(gainedWei)); 
    else
        require(cluster.send(gainedWei)); 
    gainedWei = 0;
    client.success = 1;
}
Извините, я не понял, что вы имели в виду под: «<какое-то условие> не нужно бросать, поэтому не нужно»? можно небольшой пример? @o0ragman0o
if(require(<some condition>))является недопустимым синтаксисом, так как require()не возвращает логическое значение.