V.ВЫЧИСЛЕНИЕ

Фермеры стремятся выделить все доступное дисковое пространство для консенсуса, при этом выполняя как можно меньше избыточных вычислений . Однако, чтобы быть уверенным, что они остаются в самой длинной допустимой цепочке, они должны вычислить все переходы промежуточных состояний, что подразумевает, что они также поддерживают состояние. По мере того как бремя поддержания состояния и переходов на вычисления будет возрастать, возникнут дилеммы как у фермера, так и у проверяющего , что приведет к тому, что фермеры пожертвуют безопасностью ради более высоких вознаграждений при меньших затратах, либо став легкими клиентами или присоединиться к надежному фермерскому пулу. Чтобы решить обе дилеммы, нам нужен метод, который избавит фермеров от этого бремени, но в то же время позволит им быть уверенными в том, что они расширяют самую длинную действительную цепочку. Критически важно, чтобы этот метод не ухудшал жизнеспособность, справедливость или безопасность производства блоков . Предлагаемое нами решение следует классической методике в распределенных системах разделения консенсуса и вычислений. В этой системе фермеры несут единоличную ответственность за обеспечение субъективного и вероятностного консенсуса в отношении порядка транзакции, в то время как отдельный класс узлов-исполнителей вычисляет объективный и детерминированный результат этого заказа. Исполнители отбираются путем выборов на основе ставок, отдельно от производства блоков и аналогично методу завершения блоков , предложенному Casper FFG[24]. Исполнители получают стимул, разделяя комиссионные за транзакции с фермерами, в то же время привлекаясь к ответственности с помощью системы неинтерактивных доказательств мошенничества [25] и сокращения [26]. Хотя он якобы похож на Flow и, безусловно, находится под его влиянием[27]–[29], наш подход намного проще (два, а не четыре класса ноды), сохраняет совместимость с консенсусом Накамото (в отличие от консенсуса в стиле BFT) и поддерживает предположение о безопасности честного большинства. Мы также черпаем вдохновение у авторов Truebit [30], которые первыми признали, что оптимистичные вычисления вне цепочки с резервными вариантами проверки в цепочке могут быть использованы для создания надежного децентрализованного пула майнинга, чего мы в значительной степени и добиваемся здесь. Однако, в отличие от Truebit, мы используем систему неинтерактивного доказательства мошенничества, решая дилемму верификатора совершенно другим способом. В отличие от таких протоколов, как ChainSpace [31] и LazyLedger [32], которые обеспечивают развязку путем делегирования вычислений клиентам, наша система сохраняет глобальное состояние, позволяя выполнять вызовы с перекрестными контрактами и компоновку приложений. Обратите внимание, что этот подход полностью отличается от гибридного Механизмы консенсуса POC / POS, используемые другими блокчейнами на базе хранилища. Filecoin [33] требует размещения ставок пропорционально объему хранилища в качестве предварительного условия для ведения сельского хозяйства, жертвуя неограниченный характер и динамическая доступность консенсуса Накамото. Mass обеспечивает двойную структуру стимулов, в соответствии с которой любой желающий может создавать блоки и получать награды , делая ставки или занимаясь фермерством. Вместо этого мы четко различаем механизм фермерства без разрешений для производства блоков и разрешенный механизм размещения ставок для завершения блоков.

A. Общий обзор

Мы начинаем с ограничения роли фермеров простым предоставлением субъективного порядка в отношении потенциально допустимых транзакций. Для этого фермер собирает транзакции в обычном режиме, только проверяя, что отправитель предоставил действительную подпись и способен оплатить комиссию. Когда фермер находит PoR , который удовлетворяет аудит хранилища, он объединяет все действительные транзакции в новый блок, одновременно фиксируя последнее действительное корневое предложение состояния, которое они наблюдают. Поскольку фермеры больше не вычисляют корень нового штата самостоятельно, им не нужно сохраняйте код, состояние или остатки на счетах для любых контрактов. Вместо этого они должны поддерживать только гораздо меньший набор балансов (и одноразовых номеров) для Externally Owned Accounts (EOAs). Это дает дополнительное преимущество, позволяя блокам распространяться быстрее (и снижая вероятность развилок), поскольку фермерам нужно только проверить PoR и то, содержит ли блок потенциально допустимые транзакции, прежде чем передавать блок своим одноранговым узлам. Отдельный класс узлов-исполнителей затем будет поддерживать полное состояние и применять транзакции, возвращая новые предлагаемые государственный корень. Для каждого нового блока небольшое постоянное число исполнителей выбирается путем взвешенных выборов. Любой желающий может принять участие в исполнении, синхронизировав состояние и разместив небольшой депозит. Чтобы определить, будут ли они избраны, каждый исполнитель будет использовать хэш PoR в качестве входных данных для VRF, привязанного к их депозиту и взвешенного по их доле от общей ставки. Независимо от того, будут ли они избраны или нет, каждый исполнитель затем применит каждую транзакцию к состоянию со всеми соответствующими функциями перехода к состоянию в указанном порядке квартала. По мере выполнения каждой транзакции они будут постепенно фиксироваться в корневом промежуточном состоянии, формируя трассировку выполнения, а также составляя совокупную разницу всех балансов EOA. Обратите внимание, что любой неизбранный исполнитель, который пропустит процедуру обновления состояния, не сможет предложить новый действительный корень состояния в случае, если он будет избран для какого-либо будущего блока. Затем все избранные исполнители передадут квитанцию об исполнении (ER), состоящий из доказательства VRF, корня конечного состояния, корня Меркла всех корней промежуточного состояния, трассировки выполнения, и EOA уравновешивает разницу. По прибытии и подтверждении ER, каждый фермер будет оптимистично применять разницу в балансах, отмечая при этом новый предлагаемый корень состояния, который следует ожидать (или внедрять) в следующем блоке

B. Сохранение жизнеспособности

Учитывая асинхронный характер сети, присутствие византийских участников и вероятностный характер как производства, так и выполнения блоков, мы не можем ожидать, что эти два процесса всегда будут плавно чередоваться. В случае, если фермер выбран для создания нового блока до того, как он получит действительный ER для последнего блока, мы по-прежнему позволяем им публиковать блок без ER. Это нарушение может произойти по нескольким возможным причинам: новый блок был создан вскоре после его родительского, либо до того, как выполнение могло быть завершено, или ER может полностью распространяться по сети; ни один исполнитель фактически не был избран для завершения блока; или избранный исполнитель / исполнители решили отказаться от ER, пытаясь повлиять на живучесть исполнения. Чтобы оправиться от этого события, мы просто повторно проводим выборы исполнителя для каждого нового блока, позволяя любому вновь избранному исполнителю включать всех прошлых исполнителей, необходимых для наверстывания упущенного, нового ER для последнего блока и совокупный баланс EOA. Разница. Тем временем фермеры могут продолжать проверять новые транзакции пессимистично, т.е. на основе минимально возможного баланса EOA для набора ожидающих транзакций. Хотя это может привести к тому, что некоторые транзакции будут ошибочно помечены как незаконные , это не позволит незаконной транзакции попасть в новый блок. Важно отметить, что, поскольку каждый выбор исполнителя является независимым и случайным, вероятность повторения этого события экспоненциально уменьшается для каждого нового блока. Мы также устанавливаем избирательный порог таким образом, чтобы в среднем в каждом туре избиралось небольшое постоянное число исполнителей, чтобы значительно уменьшите вероятность того, что это событие вообще произойдет. Чтобы справиться со случаем, когда противник с глубокими карманами потребляет подавляющее большинство акций, фактически не управляя исполнителем, чтобы атаковать живучесть исполнения, мы позволяем порогу выборов динамически настраиваться в соответствии с наблюдаемой доступностью исполнителей.

C. Сохранение справедливости

Фермеры равномерно распределяют вознаграждение за транзакцию со всеми исполнителями, исходя из ожидаемого количества ER для каждого блока.7 Например, если будут избраны 32 исполнителя, фермер возьмет половину всех комиссионных за транзакцию, в то время как каждый исполнитель возьмет 1/64. Фермер заинтересован в том, чтобы включить все ER, которые завершают выполнение для его родительского блока, потому что это позволит ему претендовать на большую долю вознаграждений за свой собственный блок. Например, если фермер включает только 16 из 32 ожидаемых ERs, вместо этого он получит 1/4 (а не 1/2) от общего количества вознаграждений, в то время как каждый из 16 исполнителей все равно получит 1/64. Любые оставшиеся доли затем будут депонированы на счет-сокровищницу под контролем сообщества держателей токенов с целью стимулирования дальнейшего развития протокола. В целом, невостребованные средства должны оставаться незначительными. В случае, если будет включено более 32 кандидатов, доля фермера останется прежней, в то время как исполнители будут соответственно разбавлены, чтобы обеспечить динамичное избрание порога поддерживающего правильный баланс. Критически важно, что это распределение вознаграждения может не иметь обратной силы, иначе это побудило бы эгоистичных исполнителей удерживать ERs для определенных фермеров, которые производят последующие блоки, с которыми они могут вступить в сговор. Мы отмечаем, что эта схема также совместима с делегированным или назначенным механизмом размещения ставок, но, в отличие от многих протоколов консенсуса, подтверждающих наличие доли , не имеет строгой верхней границы числа делегатов или кандидатов.

D. Обеспечение достоверности

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

  1. Начального состояния для всех учетных записей, затронутых транзакцией.

  2. Всех функции перехода состояния (т.е. код контракта).

  3. Приверженности действительному выходному состоянию.

  4. Доказательства включения Меркла для каждого из вышеперечисленных.

Любой узел, учитывая трассировку выполнения и доказательства мошенничества, может определить действительность ER с помощью:

  1. Проверка доказательств включения Меркле для входного состояния и кода на соответствие последнему допустимому корню промежуточного состояния.

  2. Применение всех функций перехода состояния к входному состоянию.

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

Если доказательство мошенничества является действительным, исполнитель, предложивший недействительный ER, увидит, что весь его депозит конфискован и помещен в "сокровищницу" протокола. Чтобы это произошло, оба недействительных ER и доказательство мошенничества должны быть включены в цепочку. Это означает, что фермеры должны ссылаться на все предлагаемые ER, которые они наблюдают, при создании нового блока, зная при этом, что все недействительные ER будут быстро удалены из реестра. Этот приведет к (сохраненной) реорганизации цепочки квитанций об исполнении, не влияя на порядок транзакций. Вместо того, чтобы включать весь ER, фермерам нужно только записать гораздо меньший заголовок, состоящий из доказательства VRF и корня Меркле по всем переходам промежуточного состояния. В ожидаемом случае, когда исполнители экономически рациональны, все ER будут действительными, и доказательства мошенничества не понадобятся. Если исполнители недобросовестны, для каждого недействительного ER необходимо будет создать отдельное доказательство мошенничества. Любой вредоносный исполнитель, контролировавший большую часть пакета акций, мог затем применить ограниченную атаку типа "denial of service" (DOS) в цепочке, создав множество различных недействительных ER, заставляя честные узлы генерировать соответствующие доказательства мошенничества и занимая драгоценное пространство блока. Если мы сделаем минимальный депозит доли исполнителя больше, чем ожидаемая стоимость простого занятия пространства блока транзакцией (т.е. Эквивалентная стоимость газа) , то всегда было бы более рационально расширять сеть, просто создавая крупные транзакции с достаточными комиссиями для хранения некоторые произвольные данные или выполнить некоторые произвольные вычисления, как это уже можно сделать сегодня в Ethereum.

E. Решение дилеммы проверяющего

Большинство схем, основанных на мошеннических доказательствах, используют вознаграждение в качестве стимула обойти сложную дилемму верификатора. Мы отмечаем, что, поскольку все мошеннические доказательства являются каноническими для одного и того же недействительного ER, любой механизм вознаграждения может быть легко запущен. Вместо того, чтобы пересылать мошеннические доказательства как есть, любой исполнитель может так же легко заявить о них, как о своих собственных. В конечном счете, это создало бы стимул для фермеров и исполнителей вступать в сговор, так что фермер, создающий блок, будет опираться на мошеннические доказательства как на свое собственное. Хотя это может быть ограничено требование внесения депозита для участия в качестве верификатора не решит проблему. Мы также могли бы попытаться выбрать одного или нескольких проверяющих по аналогичной схеме, но это значительно снизило бы эффективность генерации доказательств мошенничества. Вместо этого мы полагаемся на тот факт, что все исполнители могут выступать в качестве проверяющих при незначительных дополнительных затратах, поскольку они уже обязаны поддерживать допустимые переходы состояний, чтобы предлагать новые ERS. Если мы в дальнейшем потребуем, чтобы они раскрыли мошенничество , чтобы защитить свою долю и потребовать свою долю награды, в том случае, если они сами будут избраны, тогда мы сможем предложить более естественное решение дилеммы верификатора . Мы достигаем этого, аналогичным образом наказывая любого исполнителя , который продлевает недействительный ER без предварительной демонстрации мошенничества. Стоит отметить, что у фермеров также есть стимул включать как недействительные ER, так и соответствующие доказательства мошенничества в новый блок, так как без них любые новые действительные ER для родительского блока приниматься не будут, что снижает долю фермеров в доступных вознаграждениях. Поскольку в каждом раунде будет избираться несколько исполнителей, "ленивые" исполнители все еще могли бы, возможно, подождать, пока некоторые другие, более нетерпеливые исполнители, сначала создадут доказательства мошенничества. Если мы также потребуем , чтобы каждый ER включал обязательство по каждому доказательству мошенничества для каждого недействительного ER, засвидетельствованного предыдущим блоком, тогда мы можем гарантировать, что исполнители не смогут выпустить ER, пока они сначала не создадут (или не увидят) все необходимые доказательства мошенничества. Учитывая сетевую задержку и стохастический процесс производства блоков, любой избранный исполнитель, который ожидает всех действительных доказательств мошенничества, прежде чем опубликовать свой собственный ER, рискует остаться вне следующего блока и упускают свою долю вознаграждений. Поэтому для исполнителя разумно выполнять незначительную и редкую дополнительную работу, необходимую для создания доказательства мошенничества на местном уровне, чтобы как можно скорее выпустить свой собственный ER. В дополнение к исполнителям, любой полный узел может также отслеживать сеть и генерировать доказательства мошенничества, в силу того факта, что для выполнения функций верификатора депозит не требуется. Поскольку доказательства мошенничества являются каноническими, любой узел может генерировать и распространять их локально, не потребляя больше пропускной способности, чем если бы он просто получил их и передал дальше. Это имеет преимущество ускорения распространения доказательств мошенничества при одновременном дальнейшем усилении гарантий безопасности. Позволяя любому предложить доказательство мошенничества, мы можем обеспечить достоверность цепочки перед лицом большинства недобросовестных исполнителей, позволяя системе оставаться в безопасности до тех пор, пока один честный исполнитель остается подключенным по крайней мере к одному честному фермеру.

F. Поддержание Безопасности

Мы определяем безопасность как свойство, при котором транзакция, однажды включенная в бухгалтерскую книгу, впоследствии не может быть отменена. Консенсус Накамото обеспечивает только вероятностную безопасность благодаря правилу подтверждения k-deep, в котором говорится, что для данной состязательной доли ресурсов консенсуса вероятность того, что транзакция может быть отменена, экспоненциально уменьшается с каждым новым блоком. Наша цель - просто сохранить это свойство. Для этого мы должны сначала провести различие между незаконными и недействительными транзакциями. Строго говоря, любая сделка, которая обход механизма DOS-защиты комиссии за транзакцию является незаконным и никогда не должен включаться в бухгалтерскую книгу. Фермеры обеспечивают соблюдение законности, гарантируя, что транзакция имеет действительную подпись и может покрыть указанную плату. Затем мы определяем допустимую транзакцию как транзакцию, которая приводит к допустимому переходу состояния. Исполнители обеспечивают действительность транзакций , применяя их детерминированно в порядке, указанном фермерами. Важно признать, что недействительные транзакции , безусловно, могут быть законными и ни в коем случае не предполагать злонамеренных действий, поскольку их выполнение не гарантирует отражения того же глобального состояния, которое наблюдалось при их создании. Соответственно, недействительные транзакции просто игнорируются всеми честными исполнителями. Из этого следует, что недобросовестные исполнители могут лишь временно повлиять на безопасность цепочки, сделав недействительную транзакцию действительной, но они не могут отменить транзакцию, поскольку у них нет возможности исключить ее из заранее определенного набора потенциально допустимых транзакций. Только фермеры имеют возможность сделать это с помощью преднамеренной вилки, которая, следуя анализу Накамото, может быть выполнено только с незначительной вероятностью при достаточном k [1]. Более того, даже если в цепочку включено много недействительных идентификаторов, время, необходимое для их распознавания как таковых, всегда будет меньше k. Таким образом, наши гарантии безопасности остаются неизменными, даже в присутствии недобросовестного большинства исполнителей, учитывая, что мы поддерживаем честное большинство фермеров.

Напомним, что при оценке ER фермеры проверяют только достоверность доказательства VRF, поскольку у них нет возможности узнать , действительно ли оно отражает действительный переход состояния. Даже если они знали, что это не так, им все равно нужно было бы включить недействительный ER, чтобы на него можно было ссылаться с помощью соответствующего мошеннического доказательства . Поскольку мы ожидаем небольшое постоянное количество ER для каждого блока и предполагаем экономически мотивированных исполнителей, мы ожидаем, что в среднем случае все ER согласятся, что позволит фермерам оптимистично применять разницу в балансах EOA и продолжать собирать новые транзакции.В случае, если один или несколько экспертов не согласятся, фермер вместо этого будет пессимистично проверять новые транзакции и ждать, пока не будет получено достаточно доказательств мошенничества, чтобы исключить все, кроме одного, оставшегося действительным ER . В маловероятном случае, если все исполнители согласятся с одним и тем же недействительным ER, эти недобросовестные исполнители могут убедить фермера в том, что предложенный ER действителен только до тех пор, пока фермер не увидит действительное доказательство мошенничества, что в значительной степени зависит от задержки распространения сети. Для заданной задержки D, максимальное время, за которое фермер может увидеть доказательства мошенничества, составляет 2D плюс время генерации доказательств. Поскольку D уже должен составлять небольшую долю от ожидаемого уровня фарминга, для любого безопасного реализация консенсуса Накамото, мы можем ожидать, что с высокой вероятностью все доказательства мошенничества будут видны в течение двух блоков. Возможно, худшее, чего может добиться недобросовестный исполнитель , - это ввести фермеров в заблуждение относительно законности транзакций, представив мошенническую разницу в балансах EOA как часть недействительного ER. Это позволит им вставлять незаконные транзакции в следующий блок, предотвращая выбор многих законных транзакций. Как упоминалось ранее, фермеры оптимистично применяют разницу только в том случае, если нет конфликтующих ER для последнего блок. Это означает, что нечестной партии сначала нужно будет контролировать подавляющее большинство акций, а затем надеяться, что ни один честный исполнитель все еще не был выбран. Даже в этом случае любые незаконные транзакции все равно будут признаны таковыми честными исполнителями и будут удалены из ledger, что дорого обойдется злоумышленнику в виде утраченной доли.

G. Сублинейная синхронизация

Когда новые фермеры присоединяются к сети, они должны синхронизироваться с genesis, чтобы убедиться, что они работают над расширением самой длинной действующей цепочки. Традиционно это делалось бы путем проверки PoR и переходов состояний для каждого блока. Поскольку мы хотим, чтобы фермеру не приходилось поддерживать состояние даже во время начальной синхронизации, нам требуется альтернатива, которая все еще позволяет им быть уверенными в том, что цепочка действительна. Если бы вместо этого они синхронизировали только заголовки блоков , им все равно пришлось бы расходовать вычисления и пропускную способность линейно по высоте цепочки. Это становится еще хуже тем фактом, что мы не встраиваем кодировки или доказательства Merkle в блоки, что означает, что им придется вручную проверять каждый PoR, извлекая фрагмент и его доказательство Merkle из DHT, а затем повторно извлекать каждую кодировку из ее входных данных. Чтобы фермеры могли быть уверены, что они находятся в самой длинной цепочке, при этом им нужно только загружать и вручную проверять логарифмические блоки по высоте цепочки, мы внедряем сверхлегкий клиент, вдохновленный Flyclient [34]. Чтобы разрешить это, мы должны сначала расширить протокол таким образом, чтобы мы постепенно фиксируйте каждый новый блок, используя Merkle Mountain Range. Когда новый фермер присоединяется к сети, он запрашивает у одноранговых узлов самый последний блок, принимая его за предполагаемую высоту цепочки. Затем они итеративно делят цепочку пополам (по индексу) и случайным образом выбирают блок в левой половине, прежде чем извлекать блок из DHT, восстанавливать его полностью и вручную проверять PoR. Если все подтвердится, фермер продолжит, еще раз разделив правую половину цепочки . Если они достигнут вершины цепочки, и все блоки будут действительно, тогда с высокой вероятностью они находятся в самой длинной цепочке. Чтобы фермер был уверен, что он находится в самой длинной допустимой цепочке, при наличии нескольких цепочек-кандидатов он использует простой процесс исключения. Чтобы устранить цепочки, которые являются результатом атаки на большие расстояния, фермер сравнивает среднюю высоту решений для каждой цепочки с ожидаемой, отдавая предпочтение тем, которые находятся ближе всего. Для дальнейшего устранения цепочек , которые включают недопустимый переход состояния, увековеченный нечестным большинством, фермеру нужно только спросить каждого предлагающего проверьте последние достоверные доказательства мошенничества, которые он наблюдал. Если хотя бы один партнер честен, фермер сможет получить доказательства мошенничества для всех недействительных цепочек, оставив фермера в самой длинной действительной цепочке.

H. Оптимизация

В последующем [25], мы отмечаем, что (потенциально большая) трассировка выполнения в ER необходима только в том случае, если новый предлагаемый корень состояния недействителен, а затем только исполнителями (или любым полным узлом), поскольку они единственные, кто может генерировать соответствующее доказательство мошенничества. Фермеры, однако, должны быть уверены только в том, что трассировка выполнения доступна, чтобы любой честный исполнитель мог восстановить полную трассировку и создать доказательство мошенничества, если оно действительно недействительно. Затем мы можем потребовать, чтобы исполнители стерли код трассировки, чтобы любой узел мог быть уверен что кодирование было выполнено правильно и что доступны полные данные , в то время как для случайной выборки требуется только небольшая постоянная часть данных. Мы также отмечаем, что в ожидаемом случае только фермерам потребуется выборка данных, так как исполнители смогут сразу определить, является ли ER недействительным только по его заголовку. В то время как все честные исполнители для данного блока будут иметь одинаковое тело, помните, что размер заголовка линейно увеличивается с ожидаемым количеством избранных исполнителей для каждого блока из-за дополнительных доказательств избрания. Мы можем свести это к постоянный размер путем замены VRF неинтерактивной детерминированной схемой подписи, такой как BLS [35], которая позволила бы нам сжать все честные доказательства избрания в единый открытый ключ и единую подпись. Мы также можем реализовать одно из нескольких предложений по stateless блокчейну [36]–[38], которое позволило бы нам полностью освободить фермеров и, возможно, исполнителей от бремени поддержания состояния, а также устранить разницу в балансах EOA из ER. В настоящее время эти схемы налагают дополнительные требования безопасности и накладные расходы на вычисления для фермеров, одновременно повышая сложность пользовательского интерфейса. По мере того, как эти схемы станут более развитыми, мы ожидаем, что они могут быть использованы для устранения необходимости для фермеров полностью поддерживать баланс EOA, возможно, полностью решив дилемму фермера . Что касается доказательств мошенничества, мы отмечаем, что, хотя они редко ожидаются, они все равно могут быть довольно большими, поскольку их размер ограничен только максимальным размером кода и состояния для любой данной контрактной учетной записи, в зависимости от общего количества контрактных вызовов, которые могут быть включены в транзакцию, обычно ограниченный самим ограничением газа блока. Чтобы уменьшить размер этих входных данных, мы можем увеличить количество обязательств промежуточного состояния, необходимых для трассировки выполнения, отметив , что больший размер ER будет уменьшен с помощью схемы кодирования стирания, представленной ранее. Мы можем дополнительно уменьшить размер кода контракта, необходимого для доказательства, сохранив его в эффективном накопителе, таком как древо Merkle, способом , аналогичным предложению MAST [39].

Last updated