Являются ли монолитные смарт-контракты лучше несвязанных?

Приложение смарт-контракта, которое я пишу, следует тому, что я считаю хорошей практикой — оно отделено, так что контракт контроллера вызывает логический контракт, который вызывает контракт хранилища. Так Contract Aзвонки Contract Bзвонки Contract C.

Однако мне интересно, является ли из-за безопасности такая развязка хорошей идеей для смарт-контрактов. Это потому, что мне нужен onlyOwnerмодификатор, чтобы связать, кто вызывает мои функции (как описано здесь: https://github.com/ethereum/wiki/wiki/Solidity-Features ). На мой взгляд, было бы здорово, если бы я мог сделать что-то вроде этого:

import "Owned.sol";

contract A is Owned {

   B private b;

   function A(address B) {
       b = B(b);
   }

   function myInterface() public onlyOwner {
       a.doStuff({from: msg.sender});
   }
}

contract B is Owned {

   C private c;

   function B(address c) {
       c = C(c);
   }

   function doStuff() public onlyOwner {
       c.store(42,{from: msg.sender});
   }
}

contract C is Owned {

   int private theAnswer;

   function store(int value) public onlyOwner {
       theAnswer = value
   }
}

Однако я считаю, что не могу отправить msg.senderтаким образом. Contract AСледовательно , было бы лучше объединить Contract Bв Contract Cединый монолитный контракт, где msg.sender он действителен?

Почему бы вам просто не сделать A владельцем B, а B владельцем C?
@TjadenHess. Я хотел было написать: "да, но как?" Но на самом деле я могу передать адрес A в B и B в C в конструкторе и таким образом назначить владельца. Дох! Э-э, да - ты прав. Иногда эти вещи просто нужно проветрить, чтобы решить ;) Спасибо!
На самом деле, я бы создал B в конструкторе A вместо передачи адреса, а затем использовал msg.senderего в конструкторе B для установки владельца. Затем сделайте то же самое, создав C из конструктора B.
@TjadenHess - хорошо - это потому, что тогда B правильно владеет своим экземпляром C (например), а не владеет уже развернутым C (который тем временем может изменить свое право собственности)?
В яблочко. В некоторых случаях это может быть не то, что вы хотите, но обычно легче рассуждать о контракте, когда он не взаимодействует с каким-то произвольным контрактом.
Теперь я вспоминаю - я делал это таким образом, но причина, по которой я не делаю этого сейчас, заключается в том, что у меня заканчивались контракты на развертывание газа, которые выполняли много news. Но теперь я знаю немного больше, так что я проведу повторное расследование.
Если у вас кончается газ, то передача адресов в конструктор тоже сработает.
@TjadenHess Итак, я попытался применить newподход, и действительно, у меня закончился газ. Для этого требуется около 7 миллионов газа. Следовательно, мне нужно передавать адреса. К сожалению, выше я не понял, что я не могу передать адрес B для C, чтобы C мог сделать B своим владельцем, поскольку B сначала нужен адрес C. Существуют способы «передачи права собственности» обратно В, но все они довольно запутаны. Это возвращает меня к заголовку моего первоначального поста: не лучше ли мне избежать всей этой сложности, просто объединив все необходимые функции в один контракт? Я надеюсь, что не должны быть лучшие способы...

Ответы (1)

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


Что касается решений: возможно, распространяется Ownedна Authable:

  • mapping (address => bool) public authorised
  • modifier onlyAuthed {...}
  • function authAdd (address _addr) public onlyOwner {...}
  • function authRem (address _addr) public onlyOwner {...}

... а затем использовать Authed+ onlyAuthedвместо Owned+ onlyOwnerв производных приложениях?..

Затем вы можете развернуть части независимо друг от друга. Когда есть «полная цепочка», которую можно связать (например A->B->C[several], вы можете звонить C.authAdd(<address-of-B>)из своей ownerучетной записи.

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

Схема может быть изменена в соответствии с конкретными потребностями.


В качестве альтернативы вы можете использовать Ownable от Zeppelin и его transfer()функцию.

Это будет работать нормально, если:

  • «цепочка владения» является линейной, т. е. ни один случай, когда одно децентрализованное приложение не может быть вызвано несколькими другими; а также
  • сохранение первоначального права собственности (за развертывающей учетной записью) не требуется (например, для ядерных целей).

РЕДАКТИРОВАТЬ:

Опять же, вы можете перейти b = B(b)от конструктора к отдельной функции (например function createChildren(...) public onlyOwner onlyOnce {...}) и добавить способ распространения запроса на уже созданные дочерние элементы (например function nagForGrandChildren(...) public onlyOwner {...}). Но проблема остается: при nFGC()достижении лимита газа в блоке вызов функции придется повторить — инициировать из исходной внешней ownerучетной записи A.

Так или иначе, вам нужно будет предвидеть, что какая-то часть вашей цепочки не сможет развернуться. Выбор здесь между «что-то в будущем» или «что-то среднее».