Проверяем работает ли full-RBF в Bitcoin
У криптоматов, криптообменников, мерчантов и всех других, кто принимают биткоин, стоит задача обрабатывать платежи как можно быстрее. С учетом среднего подтверждения биткоин блока в 10 минут, возникает вопрос: можно ли засчитать получение платежа, если транзакция на депозит находится в мемпуле и еще не подтверждена? Иными словами, насколько реалистично заменить или отменить транзакцию, которая уже находится в мемпуле?
TL; DR: я развернул свою ноду Bitcoin Core v24.0, которая поддерживает full-RBF и попытался заменить транзакцию — у меня ничего не вышло.
Больше новостей про продакт-менеджмент, технологии и предпринимательство в крипте в моем телеграм канале: @grin_channel
Что такое RBF и почему это стало актуальным
RBF (replace by fee) — замена неподтвержденной транзакции новой транзакцией с более высокой комиссией сети. Под заменой имеется в виду, что новая транзакция использует тот же инпут, что и исходная.
Физический смысл RBF в том, что майнеру (создателю блока) выгодней взять транзакцию с более высокой комиссией. А так как у транзакций одинаковый инпут, то вторая транзакция становится невалидной.
Еще в 2016 год вышло обновление ноды Bitcoin Core v0.12.0, которое включило в себя поддержку Opt-in RBF. Это функция, которая позволяет создавать транзакции со специальным флагом, сигнализирующим о том, что транзакция может быть заменена. Технически это выглядит так: у каждой транзакции есть свой порядковый номер nSequence
, определяющий очередность взятия транзакций в блок. И, чтобы сделать транзакцию потенциально незаменимой, нужно было указать максимально возможный порядковый номер — 0xffffffff
. Например, блокчеин эксплорер mempool.space об этом указывает явно:
Источник: https://mempool.space/
По правилам протокола Bitcoin, все повторные транзакции с тем же инпутом должны быть отклонены и не распространяться нодами дальше по сети. Это правило называется first seen rule. В крайнем случае, так было раньше.
В декабре 2022 году вышло обновление ноды Bitcoin Core 24.0.1, которое включает в себя full-RBF. Это функция, которая позволяет нодам обрабатывать повторные транзакции и считать их легитимными. По дефолту в ноде эта функция выключена, поэтому в настройках ноды для ее активации необходимо задать параметр mempoolfullrbf=1
На февраль 2023 года почти 30% всех нод Bitcoin перешли на версию 24.0.1:
Источник: https://bitnodes.io/dashboard/1y/
Согласно исследованию, из всех нод версии 24.0.1 минимум 17% активировали full-RBF.
Пошаговая инструкция по замене транзакций
Я решил развернуть ноду Bitcoin v24.0.1 и попробовать заменить транзакцию. Ниже поэтапный план действий.
Системные требования Bitcoin Core с bitcoin.org:
Disk space. 350 GB.
Download. 500 MB/day (15 GB/month)
Upload. 5 GB/day (150 GB/month)
Memory (RAM) 1 GB.
System. Desktop. Laptop. Some ARM chipsets >1 GHz.
Operating system. Windows 7/8.x/10. Mac OS X.
У меня по факту заняло около 480 GB, поэтому лучше заложить дискового пространства побольше.
Шаг 1. Скачиваем ноду Bitcoin Core v24.0.1
Скачиваем пропатченную ноду Bitcoin Core v24.0.1. Нода специально подключается к пирам, которые поддерживают full-RBF и способствуют распространению повторных транзакций по сети:
git clone -b full-rbf-v24.0.1 https://github.com/petertodd/bitcoin.git
Детальней об этой ноде можно прочитать здесь. Либо можно скачать оригинальную ноду и затем в настройках указать пиры, у которых стоит full-RBF. Об этом будет еще описано ниже.
Шаг 2. Компилируем исходники и запускаем ноду
Вначале устанавливаем все необходимые зависимости.
Linux:
sudo apt-get install automake autotools-dev bsdmainutils build-essential ccache clang gcc git libboost-dev libboost-filesystem-dev libboost-system-dev libboost-test-dev libevent-dev libminiupnpc-dev libnatpmp-dev libqt5gui5 libqt5core5a libqt5dbus5 libsqlite3-dev libtool libzmq3-dev pkg-config python3 qttools5-dev qttools5-dev-tools qtwayland5 systemtap-sdt-dev
Mac OS:
brew install automake boost ccache git libevent libnatpmp libtool llvm miniupnpc pkg-config python qrencode qt@5 sqlite zeromq
Дальше компилируем ноду Bitcoin:
./autogen.sh
./configure
make
Если вы хотите запустить компиляцию сразу на нескольких ядрах, то для команды make
необходимо задать соответствующие параметры:
Linux
make -j "$(($(nproc) + 1))"
Mac OS
make -j "$(($(sysctl -n hw.physicalcpu) + 1))"
У меня на 8 GB RAM и 4 ядрах компиляция заняла около 15 минут. Если у вас на этом этапе возникли проблемы, то можете посмотреть раздел Troubleshooting здесь.
Шаг 3. Создаем конфигурационный файл bitcoin.conf
Файл необходимо создать в корневой папке ./bitcoin
. Есть даже онлайн генератор конфигов, мне во время эксперимента понадобились следующие параметры:
mempoolfullrbf=1 #Включает full-RBF функционал
txindex=1 #Индексирует внешние транзакции, которые не принадлежат кошельку ноды
datadir= #Если необходимо сменить директорию, куда нода будет загружать все данные
Остановлюсь подробней на параметре txindex=1
. Если не включить этот параметр, то нода не сможет обращаться к входным и выходным параметрам транзакций, которые не относятся к кошельку ноды. Это может понадобиться, когда вы пытаетесь отправить повторную транзакцию с использованием того же входа, который по факту является ссылкой на выход внешней транзакции. Этот параметр потребует дополнительно порядка 20 GB дискового пространства под хранение индексированных данных.
Если у вас оригинальная нода, и вы хотите добавить пиры с включенным full-RBF, то в конфигурационный файл добавьте еще следующие параметры:
addnode=full-rbf1.btc.petertodd.net
addnode=full-rbf2.btc.petertodd.net
addnode=full-rbf3.btc.petertodd.net
addnode=full-rbf4.btc.petertodd.net
Список пиров с включенным full-RBF взят здесь.
Шаг 4. Запускаем ноду и создаем кошелек
Запускаем ноду при помощи команды ./bitcoind -daemon
. Если вы не хотите запускать ноду в фоновом режиме, то запускайте без параметра -daemon
Дальше нода должна начать синхронизацию, у меня весь процесс занял порядка трое суток.
Обращаться к ноде можно при помощи bitcoin-cli
. Например, посмотреть сколько уже скачено блоков можно следующей командой: ./bitcoin-cli getblockcount
. Со всеми командами можно ознакомиться здесь.
После полной синхронизации необходимо создать кошелек. Это можно сделать разными способами (импортировать, сгенерировать), например, создать командой createwallet:
./bitcoin-cli createwallet "testwallet"
Шаг 5. Подготавливаем скрипт
Я использовал python-скрипты отсюда.
Для начала стоит убедиться, что вы можете обращаться к локальной Bitcoin ноде через python-bitcoinlib
:
python3 /lib/python-bitcoinlib/examples/ssl-rpc-connection.py
Дальше можно взять за основу doublespend.py
и сделать следующее:
Отправить первую транзакцию с network fee значительно меньшим, чем у текущих транзакций в мемпуле. Так, транзакция «застрянет» в мемпуле и не попадет в блок;
Подождать минуту, пока транзакция распространяется по сети;
Отправить вторую транзакцию с network fee в разы превышающим текущих транзакций в мемпуле. Так, у майнера будет мотивация взять именно повторную транзакцию в блок.
Что в итоге получилось
Я проводил эксперимент несколько раз — результат был одинаков. Рассмотрим на примере одной из итераций:
Время создания | Network fee | |
Транзакция №1 | 00:00 | 0.0000113 BTC (0.26$) |
Транзакция №2 | 00:19 | 0.004068 BTC (±94$) |
Первую транзакцию я отправил с network fee = 0.26$. Это значительно ниже рыночных условий. Несмотря на то, что вторая транзакция имела fee в 94$, майнеры (создатели блоков) все равно ее не брали. То есть replace-by-fee не сработал.
Примечательно, как блокчеин эксплореры реагировали на повторные транзакции. В основном все отображали только первую транзакцию (например, mempool.space или blockchair). Эксплорер Blockcypher отображает повторные транзакции и предупреждает о double-spend:
Источник: https://live.blockcypher.com/
Я предполагаю, что майнеры не могут взять повторную транзакцию в блок, так как этот блок будет отвергнут большинством участников сети. И пока Bitcoin Core v24.0.1 с включенным full-RBF стоит у меньшинства участников, замена транзакций работать не будет.
Если вам понравилась статья, то подписывайтесь на мой телеграм канал, где я рассказываю про продакт-менеджмент, технологии и предпринимательство в крипте: @grin_channel