Три перехода Эфириума
Поблагодарить за перевод, можно подписавшись на канал Crypto_Track
Выражаю особую благодарность Дэну Финлею, Карлу Флершу, Дэвиду Хоффману и командам Scroll и SoulWallet за отзывы, обзоры и предложения.
По мере того как Ethereum переходит от молодой экспериментальной технологии к зрелому техническому стеку, способному действительно предоставить открытое, глобальное и свободное использование обычным пользователям, существуют три основных технических перехода, которые необходимо осуществить в стеке примерно одновременно:
- Переход к масштабированию L2 – все переходят на rollup(ы);
- Переход на использование безопасных кошельков –все переходят на кошельки, основанные на смарт-контрактах;
- Переход к конфиденциальности – обеспечение доступности конфиденциальных переводов средств и уверенность в том, что все другие разрабатываемые инструменты (социальное восстановление, идентификация, репутация) сохраняют конфиденциальность
Треугольник перехода экосистемы. Можно выбрать только 3 из 3.
Без первого, Ethereum потерпит неудачу, потому что каждая транзакция будет стоить 3,75 доллара США (82,48 доллара США, если наступит очередной бычий цикл), и каждый продукт, стремящийся к массовому рынку, неизбежно забудет о цепи и примет централизованные обходные пути для всего.
Без второго, Ethereum потерпит неудачу, поскольку пользователям неудобно хранить свои средства (и нематериальные активы), и все перейдут на централизованные биржи.
Без третьего, Ethereum потерпит неудачу, потому что делать все транзакции (POAP и т.д.) доступными публично для абсолютно любого человека является слишком высокой жертвой конфиденциальности для многих пользователей, и все перейдут на централизованные решения, которые хотя бы частично скрывают их данные.
Эти три перехода имеют решающее значение по вышеуказанным причинам. Но они также являются сложными из-за интенсивной координации, необходимой для их надлежащего решения. Необходимо не только улучшать функциональность протокола, но в некоторых случаях требуется довольно фундаментальное изменение способа взаимодействия с Ethereum, что требует значительных изменений со стороны приложений и кошельков.
Эти три перехода радикально изменят взаимоотношения между пользователями и адресами
В мире масштабирования L2 пользователи будут существовать на множестве L2-решений. Вы являетесь членом ExampleDAO, который существует на платформе Optimism? Тогда у вас есть учетная запись на Optimism! У вас есть CDP в системе стейблкоина на платформе ZkSync? Тогда у вас есть учетная запись на ZkSync! Вы когда-нибудь пробовали какое-нибудь приложение, которое случайно появилось на Kakarot? Тогда у вас есть учетная запись на Kakarot! Времена, когда у пользователя был только один адрес, пройдут.
Согласно данным из моего кошелька Brave, ETH у меня хранится в четырех местах. И да, Arbitrum и Arbitrum Nova отличаются друг от друга. Не волнуйтесь, со временем все станет еще более запутанным!
Кошельки со смарт-контрактами усложняют работу, значительно затрудняя использование одного и того же адреса в L1 и различных L2. Сегодня большинство пользователей используют сторонние учетные записи, чей адрес буквально является хэшем открытого ключа, который используется для проверки подписей, так что между L1 и L2 ничего не меняется. Однако, с использованием кошельков на основе смарт-контрактов, становится сложнее сохранять только один адрес. Хотя было проделано много работы, чтобы попытаться превратить адреса в хэши кода, которые могут быть эквивалентны в разных сетях, в первую очередь CREATE2 и ERC-2470 singleton factory, трудно добиться идеальной работы этой системы. Некоторые L2-решения (например, "тип 4 ZK-EVM") не совсем эквивалентны EVM и часто используют Solidity или промежуточный ассемблер вместо этого, что препятствует достижению эквивалентности хэшей. И даже когда у вас может быть эквивалентность хэшей, возможность смены владельца кошельков при смене ключей создает другие непредсказуемые последствия.
Конфиденциальность требует, чтобы у каждого пользователя было еще больше адресов, и может даже измениться то, с какими типами адресов мы имеем дело. Если предложения о скрытых адресах будут широко приняты, то вместо того, чтобы у каждого пользователя было всего несколько адресов или по одному адресу на каждый L2, у пользователей может быть по одному адресу на каждую транзакцию. Другие схемы конфиденциальности, даже существующие, такие как Tornado Cash, изменяют способ хранения активов по-другому: средства многих пользователей хранятся в одном и том же смарт-контракте (и, следовательно, по одному и тому же адресу). Чтобы отправить средства конкретному пользователю, пользователи должны полагаться на внутреннюю систему адресации схемы конфиденциальности.
Как мы видели, каждый из трех переходов по-разному ослабляет ментальную модель "один пользователь ~ = один адрес", и некоторые из этих эффектов приводят к сложности выполнения переходов. Два сложных момента:
- Если вы хотите кому-то заплатить, как вы получите информацию о том, как им заплатить?
- Если у пользователей много активов, хранящихся в разных местах в разных цепях, как образом они осуществляют смену ключей и социальное восстановление?
Три перехода и платежи внутри цепи (идентификация личности)
У меня есть монеты на Scroll, и я хочу заплатить за кофе (если "я" написано буквально, имея в виду меня, автора этой статьи, то "кофе" – это, конечно, метонимия для "зеленого чая"). Вы продадите мне кофе, но вы настроены только на получение монет на Taiko. И че делать?
- Получающие кошельки (которые могут быть продавцами, но также могут быть и обычными физическими лицами) очень стараются поддерживать каждый L2 и имеют некоторую автоматизированную функциональность для асинхронной консолидации средств.
- Получатель указывает свой L2 вместе с адресом, и кошелек отправителя автоматически направляет средства к целевому L2 с помощью некоторой системы межсетевого моста между L2.
Конечно, эти решения можно комбинировать: получатель предоставляет список L2, которые он готов принять, а кошелек отправителя вычисляет платеж, который может включать либо прямую отправку, если им повезет, или в противном случае – маршрутизацию через межсетевой мост между L2.
Но это только один пример ключевой проблемы, с которой сталкиваются три перехода: простые действия, такие как оплата кому-либо, начинают требовать гораздо больше информации, чем просто 20-байтовый адрес.
Переход к кошелькам на основе смарт-контрактов, к счастью, не является большой нагрузкой на систему адресации, но в других частях стека приложений все еще существуют некоторые технические проблемы, которые необходимо проработать. Кошельки необходимо будет обновить, чтобы убедиться, что они не отправляют только 21000 газа вместе с транзакцией, и еще более важно будет убедиться, что принимающая платеж сторона кошелька отслеживает не только переводы ETH из EOAS, но и ETH, отправленные с помощью кода смарт-контракта. Приложения, которые полагаются на предположение, что владение адресом является неизменяемым (напр. NFT, которые запрещают смарт-контракты для обеспечения выплаты роялти), должны будут найти другие способы достижения своих целей. Кошельки на основе смарт-контрактов также упростят некоторые вещи – в частности, если кто-то получит только токен ERC20, отличный от ETH, он сможет использовать платежные системы ERC-4337 для оплаты газа этим токеном.
С другой стороны, конфиденциальность вновь создает серьезные проблемы, с которыми мы на самом деле еще не сталкивались. Оригинальная Tornado Cash не создавала ни одной из этих проблем, поскольку не поддерживала внутренние переводы: пользователи могли только вносить депозиты в систему и выводить из нее средства. Однако, как только можно будет осуществлять внутренние переводы, пользователям необходимо будет использовать схему внутренней адресации системы конфиденциальности. На практике "информация о платеже" пользователя должна содержать как (i) некий "открытый ключ для расходов", обязательство хранить секрет, который получатель может использовать для расходов, так и (ii) способ, с помощью которого отправитель может отправить зашифрованную информацию, которую только получатель может расшифровать, чтобы помочь ему обнаружить платеж.
Протоколы скрытых адресов основаны на концепции мета-адресов, которые работают следующим образом: одна часть мета-адреса – это закрытая версия ключа отправителя, а другая часть – ключ шифрования отправителя (хотя минимальная реализация могла бы сделать эти два ключа одинаковыми).
Схематический обзор абстрактной схемы скрытых адресов, основанной на шифровании и ZK-SNARKs.
Ключевой урок здесь заключается в том, что в экосистеме, ориентированной на конфиденциальность, у пользователя будут как открытые ключи для расходов, так и открытые ключи для шифрования, и "платежная информация" пользователя должна включать оба ключа. Есть также веские причины, помимо платежей, для развития в этом направлении. Например, если мы хотим, чтобы электронная почта была зашифрована на основе Ethereum, пользователям нужно будет публично предоставить какой-либо ключ шифрования. В "мире EOA" мы могли бы повторно использовать ключи учетной записи для этого, но в безопасном мире смарт-контрактов и кошельков у нас, вероятно, должна быть более четкая функциональность для этого. Это также помогло бы сделать идентификацию на основе Ethereum более совместимой с децентрализованными экосистемами конфиденциальности, отличными от Ethereum, в первую очередь с ключами PGP.
Три перехода и восстановление ключа
Стандартный способ внедрения изменений в ключи и социального восстановления в мире, где на каждого пользователя приходится много адресов, заключается в том, чтобы просто попросить пользователей запустить процедуру восстановления для каждого адреса отдельно. Это можно сделать в один клик: кошелек может включать программное обеспечение для выполнения процедуры восстановления по всем адресам пользователя одновременно. Однако даже при таких упрощениях UX примитивное многоадресное восстановление имеет три проблемы:
- Непрактичность в расходовании газа: это говорит само за себя.
- Контрфактические адреса: адреса, для которых смарт-контракт еще не был опубликован (на практике это будет означать учетную запись, с которой вы еще не отправляли средства). У вас, как у пользователя, есть потенциально неограниченное количество контрфактических адресов: один или несколько на каждом L2, включая L2, которые еще не существуют, и целый другой бесконечный набор контрафактных адресов, возникающих из схем скрытых адресов.
- Конфиденциальность: если пользователь намеренно имеет много адресов, чтобы избежать их привязки друг к другу, он, конечно же, не хочет публично связывать их все, восстанавливая их в одно и то же время или примерно в одно и то же время!
Решение у этих проблем непростое. К счастью, существует несколько элегантное решение, которое работает достаточно хорошо: архитектура, разделяющая логику проверки и хранение активов.
У каждого пользователя есть контракт хранилища ключей, который существует в одном месте (это может быть либо главная сеть, либо конкретный L2). Затем у пользователей появляются адреса на разных L2s, где логика проверки каждого из этих адресов является указателем на контракт хранилища ключей. Расходы с этих адресов потребовали бы подтверждения, входящего в контракт хранилища ключей, с указанием текущего (или, что более реалистично, очень недавнего) открытого ключа расходов.
Доказательство может быть реализовано несколькими способами:
- Прямой доступ L1 только для чтения внутри L2. Можно изменить L2s, чтобы дать им возможность напрямую считывать состояние L1. Если контракт хранилища ключей находится на L1, это будет означать, что контракты внутри L2 могут получить доступ к хранилищу ключей "бесплатно"
- Ветви Меркла. Ветви Меркла могут доказывать состояние L1 для L2 или состояние L2 для L1, или вы можете объединить оба варианта, чтобы доказать части состояния одного L2 для другого L2. Основным недостатком доказательств Меркла являются высокие затраты газа из-за длины доказательства: потенциально 5 кБ для доказательства, хотя в будущем это уменьшится до < 1 кБ благодаря деревьям Веркла.
- ZK-SNARKs. Вы можете снизить затраты на передачу данных, используя ZK-SNARK ветви Меркла вместо самой ветки. Возможно создание техник агрегации вне цепи (например, на основе EIP-4337), чтобы одно единственное доказательство состояния ZK-SNARK проверяло все доказательства состояния межцепочек в блоке.
- Обязательства KZG. Либо L2s, либо схемы, построенные поверх них, могли бы внедрить систему последовательной адресации, позволяющую получать доказательства состояния внутри этой системы длиной всего 48 байт. Как и в случае с ZK-SNARKs, схема с несколькими доказательствами может объединить все эти доказательства в одно доказательство для каждого блока.
Если мы хотим избежать создания одного доказательства для каждой транзакции, мы можем реализовать более легкую схему, которая требует только межцепного доказательства L2 для восстановления. Расходы из учетной записи будут зависеть от ключа расходов, соответствующий открытый ключ которого хранится в этой учетной записи, но для восстановления потребуется транзакция, которая копирует текущий открытый ключ для расходов в хранилище ключей. Средства на контрфактических адресах в безопасности, даже если ваши старые ключи таковыми не являются: "активация" контрфактического адреса для превращения его в рабочий контракт потребует создания межцепочечного доказательства для копирования текущего открытого ключа для расходов. Эта ветка на форумах Safe описывает, как может работать подобная архитектура.
Для обеспечения конфиденциальности в такой схеме, мы просто шифруем указатель, и все наши доказательства происходят внутри ZK-SNARKs:
Проделав дополнительную работу (например, используя эту работу в качестве отправной точки), мы могли бы также исключить большую часть сложности ZK-SNARKs и создать более простую схему, основанную на KZG.
Эти схемы могут быть сложными. К плюсам можно отнести то, что между ними существует множество потенциальных синергетических эффектов. Например, концепция "контрактов хранилища ключей" также могла бы стать решением проблемы "адресов", упомянутой в предыдущем разделе: если мы хотим, чтобы у пользователей были постоянные адреса, которые не меняются каждый раз, когда пользователь обновляет ключ, мы могли бы использовать скрытые мета-адреса, ключи шифрования, и другую информацию в контракт хранилища ключей и использовать адрес контракта хранилища ключей в качестве "адреса" пользователя.
Множество объектов вторичной инфраструктуры нуждается в обновлении
Использование ENS обходится дорого. Сегодня, в июне 2023 года, ситуация не так уж плоха: комиссия за транзакцию значительна, но она все еще сопоставима с платой за домен ENS. Регистрация zuzalu.eth обошлась мне примерно в 27 долларов, из которых 11 долларов составили комиссионные за транзакцию. Но если наступит еще один бычий рынок, комиссии взлетят до небес. Даже без повышения цен на ETH плата за газ, вернувшаяся к 200 gwei, повысила бы плату за регистрацию домена tx до 104 долларов. Итак, если мы хотим, чтобы люди действительно применяли ENS, особенно для таких случаев использования, как децентрализованные социальные сети, где пользователи требуют почти бесплатной регистрации (и плата за домен ENS не является проблемой, потому что эти платформы предлагают своим пользователям поддомены), нам нужно, чтобы ENS работала на L2.
К счастью, команда ENS активизировалась, и ENS на L2 действительно происходит! ERC-3668 (он же "стандарт CCIP") вместе с ENSIP-10 обеспечивают возможность автоматической проверки поддоменов ENS на любом L2. Стандарт CCIP требует создания смарт-контракта, который описывает метод проверки достоверности данных на L2, и домен (например, Optinames использует ecc.eth) может быть передан под контроль такого контракта. Как только контракт CCIP контролирует ecc.eth на L1, доступ к некоторому поддомену.ecc.eth автоматически потребует поиска и проверки доказательства (например. ветвь Меркла) состояния в L2, в котором фактически хранится этот конкретный поддомен.
На самом деле получение доказательств предполагает переход к списку URL-адресов, хранящихся в контракте, что, по общему признанию, похоже на централизацию, хотя я бы сказал, что на самом деле это не так: это модель доверия 1 из N (недопустимые доказательства перехватываются логикой проверки в функции обратного вызова контракта CCIP, и, как пока хотя бы один из URL-адресов возвращает действительное доказательство, все в порядке). Список URL-адресов может содержать десятки из них.
Усилия ENS CCIP – это история успеха, и ее следует рассматривать как признак того, что радикальные реформы того рода, в которых мы нуждаемся, действительно возможны. Но предстоит провести гораздо больше реформ на прикладном уровне. Несколько примеров:
- Множество dapps зависят от пользователей, предоставляющих подписи вне цепочки. С внешними учетными записями (EOAS) это легко. ERC-1271 предоставляет стандартизированный способ сделать это для кошельков на базе смарт-контрактов. Однако многие dapps по-прежнему не поддерживают ERC-1271; им это потребуется.
- Dapps, которые используют "это EOA?" для различения пользователей и контрактов (например, для предотвращения передачи или принудительного взыскания роялти), прекратят работу. В целом, я не советую пытаться найти здесь чисто техническое решение; выяснение того, является ли конкретная передача криптографического контроля передачей бенефициарного права собственности, является сложной проблемой и, вероятно, неразрешимой без обращения к каким-либо автономным механизмам, управляемым сообществом. Скорее всего, приложениям придется меньше полагаться на предотвращение переводов и больше на такие методы, как налоги Харбергера.
- Необходимо будет улучшить то, как кошельки взаимодействуют с расходами и ключами шифрования. В настоящее время кошельки часто используют детерминированные подписи для генерации ключей, специфичных для конкретного приложения: подписывая стандартный одноразовый номер (напр., хэш имени приложения) с закрытым ключом EOA генерирует детерминированное значение, которое не может быть сгенерировано без закрытого ключа, и поэтому оно безопасно в чисто техническом смысле. Однако эти методы "непрозрачны" для кошелька, что не позволяет кошельку осуществлять проверки безопасности на уровне пользовательского интерфейса. В более зрелой экосистеме подписание, шифрование и связанные с ними функциональные возможности должны будут обрабатываться кошельками более четко.
- Легковесные клиенты (напр., Helios) должен будет проверить L2s, а не только L1. Сегодня легковесные клиенты сосредоточены на проверке допустимости заголовков L1 (используя протокол синхронизации легковесного клиента) и проверке ветвей Меркла состояния L1 и транзакций, основанных на заголовке L1. Завтра им также нужно будет проверить доказательство состояния L2, основанное на корневом хэше состояния, хранящемся в L1 (более продвинутая версия этого на самом деле будет рассматривать предварительные подтверждения L2).
Кошельки должны будут обеспечивать безопасность как активов, так и данных
Сегодня кошельки используются для защиты активов. Все работает внутри цепи, и единственное, что нужно защищать кошельку, – это закрытый ключ, который в настоящее время охраняет эти активы. Если вы измените ключ, вы можете безопасно опубликовать свой предыдущий закрытый ключ в Интернете на следующий день. Однако в мире ZK это уже не так: кошелек не просто защищает учетные данные для аутентификации, он также хранит ваши данные.
Мы увидели первые признаки такого мира с помощью Zupass, системы идентификации на базе ZK-SNARK, которая использовалась в Zuzalu. У пользователей был закрытый ключ, который они использовали для аутентификации в системе, который можно было использовать для создания базовых доказательств, таких как "докажите, что я житель Зузалу, не раскрывая, какой именно". Но поверх системы Zupass также начали создаваться другие приложения, в первую очередь марки (версия POAPs от Zupass).
Одна из моих многочисленных марок Zupass, подтверждающая, что я являюсь гордым членом Team Cat.
Ключевая особенность, которую марки предлагают по сравнению с POAP, заключается в том, что марки являются частными: вы храните данные локально, и вы подтверждаете печать (или некоторые вычисления над марками) кому-либо только в том случае, если хотите, чтобы у них была эта информация о вас. Но это создает дополнительный риск: если вы потеряете эту информацию, вы потеряете и свои марки.
Конечно, проблема хранения данных может быть сведена к проблеме хранения единственного ключа шифрования: какая-то третья сторона (или даже цепочка) может хранить зашифрованную копию данных. Это имеет то удобное преимущество, что предпринимаемые вами действия не приводят к изменению ключа шифрования и, следовательно, не требуют каких-либо взаимодействий с системой, обеспечивающей сохранность вашего ключа шифрования. Но даже несмотря на это, если вы потеряете свой ключ шифрования, вы потеряете все. И, с другой стороны, если кто-то увидит ваш ключ шифрования, он увидит все, что было зашифровано с помощью этого ключа.
Фактическое решение Zupass состояло в том, чтобы побудить людей хранить свой ключ на нескольких устройствах (например, ноутбуке и телефоне), поскольку вероятность того, что они потеряют доступ ко всем устройствам одновременно, невелика. Мы могли бы пойти дальше и использовать совместное использование секретов для хранения ключа, разделенного между несколькими хранителями.
Такой вид социального восстановления через MPC не является достаточным решением для кошельков, поскольку это означает, что не только нынешние защитники, но и предыдущие защитники могут вступить в сговор с целью кражи ваших активов, что является неприемлемо высоким риском. Но утечка конфиденциальной информации, как правило, представляет меньший риск, чем полная потеря активов, и кто-то с высокими требованиями к конфиденциальности всегда может пойти на более высокий риск потери, не создавая резервную копию ключа, связанного с этими действиями, требующими соблюдения конфиденциальности.
Чтобы не перегружать пользователя сложной системой с несколькими путями восстановления, кошелькам, поддерживающим социальное восстановление, вероятно, потребуется управлять как восстановлением активов, так и восстановлением ключей шифрования.
Вернемся к идентификации личности
Одним из общих следствий этих изменений является то, что концепция "адреса", криптографического идентификатора, который вы используете для представления "себя" в блокчейне, должна будет радикально измениться. "Инструкции по взаимодействию со мной" больше не будут просто ETH-адресом; они должны быть в некоторой форме, комбинацией нескольких адресов на разных L2, скрытых мета-адресов, ключей шифрования и других данных.
Один из способов сделать это – сделать ENS вашей идентификационной информацией: ваша запись ENS может просто содержать всю эту информацию, и если вы отправите кому-нибудь bob.eth (или bob.ecc.eth, или ...), они смогут просмотреть и увидеть все о том, как платить и взаимодействовать с вами, включая более сложными междоменными способами и с сохранением конфиденциальности.
Но у этого подхода, ориентированного на ENS, есть два слабых места:
- Слишком многое связано с твоим именем. Ваше имя – это не вы, ваше имя - это один из многих ваших атрибутов. Должна быть возможность изменить свое имя, не перемещаясь по всему вашему личному профилю и не обновляя целую кучу записей во многих приложениях.
- У вас не может быть ненадежных псевдонимов. Одной из ключевых UX-функций любого блокчейна является возможность отправлять монеты людям, которые еще не взаимодействовали с цепочкой. Без такой функциональности есть порочный круг: взаимодействие с цепочкой требует оплаты комиссионных за транзакции, что требует... у вас уже есть монеты. ETH-адреса, включая адреса смарт-контрактов с CREATE2, имеют эту функцию. Имена ENS этого не делают, потому что, если два боба вне цепочки решают, что они bob.ecc.eth, нет никакого способа выбрать, какой из них получит это имя.
Одним из возможных решений является включение большего количества элементов в контракт хранилища ключей, упомянутый в архитектуре ранее в этом посте. Контракт хранилища ключей мог бы содержать различную информацию о вас и о том, как с вами взаимодействовать (а с CCIP часть этой информации могла бы быть вне цепочки), и пользователи использовали бы свой контракт хранилища ключей в качестве основного идентификатора. Но фактические активы, которые они получают, будут храниться в самых разных местах. Контракты хранилища ключей не привязаны к имени, и они не противоречат действительности: вы можете сгенерировать адрес, который, как можно доказать, может быть инициализирован только контрактом хранилища ключей с определенными фиксированными начальными параметрами.
Другая категория решений связана с полным отказом от концепции адресов, ориентированных на пользователя, в духе платежного протокола Bitcoin. Одна из идей состоит в том, чтобы в большей степени полагаться на прямые каналы связи между отправителем и получателем; например, отправитель мог бы отправить ссылку на заявку (либо в виде явного URL-адреса, либо QR-кода), которую получатель мог бы использовать для принятия платежа по своему усмотрению.
Независимо от того, кто действует первым – отправитель или получатель, большая зависимость от кошельков, непосредственно генерирующих актуальную платежную информацию в режиме реального времени, может уменьшить трения. Тем не менее, постоянные идентификаторы удобны (особенно с ENS), а предположение о прямой связи между отправителем и получателем на практике действительно сложно, и поэтому в конечном итоге мы можем столкнуться с комбинацией различных методов.
Во всех этих проектах первостепенное значение имеет обеспечение децентрализации и понятности для пользователей. Нам нужно убедиться, что пользователи имеют легкий доступ к актуальному представлению о том, каковы их текущие активы и какие сообщения были опубликованы, предназначенные для них. Эти представления должны зависеть от открытых инструментов, а не от проприетарных решений. Потребуется кропотливая работа, чтобы не допустить превращения более сложной платежной инфраструктуры в непрозрачную "башню абстракции", где разработчикам трудно разобраться в происходящем и адаптировать ее к новым контекстам. Несмотря на трудности, достижение масштабируемости, безопасности кошелька и конфиденциальности для обычных пользователей имеет решающее значение для будущего Ethereum. Речь идет не только о технической осуществимости, но и о реальной доступности для обычных пользователей. Нам нужно преодолеть эту сложность.
Перевод подготовлен каналом Crypto_Track
Ссылка на статью: https://vitalik.eth.limo/general/2023/06/09/three_transitions.html