Как работают кроссчейн мосты | 4
Сегодня у нас заключительная статья разбора работы кроссчейн мостов. Перевод данной статьи ТЫК
Начнем!
Эта статья посвящена объяснению того, как Wormhole предотвращает атаки повторного воспроизведения VAA (т.е. одно и то же сообщение никогда не может быть доставлено дважды в блокчейн назначения)
Это чрезвычайно важно, поскольку в противном случае злоумышленники могут украсть токены, получая токены с одним и тем же VAA многократно
Как предотвратить двойную доставку одного и того же сообщения (повтор VAA)?
По сути, каждый успешно погашенный VAA должен запоминаться глобально, поддерживая он-чейн флаг, указывающий на то, что VAA уже был погашен
Любые транзакции, которые пытаются повторно использовать VAA, отмеченные флагом is_already_redeemed, будут отклонены
Далее мы объясним, как это реализовано на Solana и Ethereum
На Solana функции доставки конечного сообщения (complete_native и complete_wrapped) принимают входной аккаунт PDA claim и используют ее для предотвращения двойного подписания VAA:
При вызове, аккаунт claim не должен быть инициализирован:
Функция consume вызывается для инициализации и проверки достоверности аккаунта claim:
Аккаунт claim - это PDA, определяемый по emitter_address, emitter_chain и sequence из VAA:
Аккаунт claim имеет флаг claimed, который становится true после инициализации (строка 87):
Благодаря вышеизложенному, Wormhole гарантирует, что каждый VAA с уникальной комбинацией (emitter_address, emitter_chain и sequence) создает уникальный аккаунт claim, который может быть успешно использован только один раз
Аналогично на Ethereum, Wormhole ведет глобальный mapping completedTransfers, в которой хранятся хэши всех завершенных VAA:
Хеш VAA - это хеш keccak256 на байтах VAA (за исключением подписей опекунов):
Это гарантирует, что каждый хэш VAA уникален для одного и того же сообщения, даже если опекуны разные
При каждом вызове доставки сообщения проверяется, помечен ли уже хэш VAA (строка 497 isTransferCompleted), и прерывается, если true, иначе доставляется сообщение и помечается хэш (строка 498 setTransferCompleted)
В приведенном выше примере _state.completedTransfers - это mapping в глобальном хранилище, и он должен обновляться при каждой успешной передаче сообщения:
Обратите внимание, что в Ethereum операции с глобальным хранилищем (SSTORE) требуют наибольших затрат газа. Это объясняет, почему погашение токена обходится дорого. Например, в следующей транзакции вызов completeTransfer стоит $6,81 (270K газа):
Надеюсь статья была интересной и понятной!