Use cases.Навеяно
этой статьёй.
В данном посте мультисигнатурные адреса буду обозначать так: {A1,...,An}m или просто {A1,...,An} если n == m.
1. Наследство/резервный вывод.
Создаём и подписываем транзакцию
TxR[0]: A1,...,An → R; TxR[0].nlocktime устанавливаем, допустим, на год вперёд
Транзакцию передаём получателю сразу. При приближении текущего времени к TxR0.nlocktime переводим средства на любой свой адрес (хоть на тот же самый):
и выпускаем новую резервную транзакцию
TxR[1]: (id(TxT[1]),0)A → R; TxR[1].nlocktime = currtime + delay
Для последующих переводов:
TxT[i]: (id(TxT[i-1]),0)A → A
TxR[i]: (id(TxT[i]),0)A → R; TxR[i].nlocktime = currtime + delay
Т.к. идентификатором непотраченных средств является (txid,vout), а не адрес, то текущая транзакция TxR[ i ] в момент очередного перевода средств становится недействительной, и после каждого перевода нужно выпускать новую резервную транзакцию.
Получатель не сможет задействовать резервную транзакцию до времени разблокирования; нам остаётся лишь следить за тем, чтобы не пропускать моменты TxR[ i ].nlocktime.
2. Хранение биткоинов на разных адресах (принадлежащих разным кошелькам) одновременно.
A1 и A2 находятся на разных кошельках и на разных компьютерах. Для кражи этих средств злоумышленнику потребуется взломать оба.
При необходимости можно выпустить резервную транзакцию к Tx1
TxR: (id(Tx1),0){A1,A2} → F; TxR.nlocktime = currtime + delay
Например, во избежание потери средств при поломке/краже одного из устройств и отсутствии бэкапов (что не отменяет необходимости бэкапить ключ адреса F). Или если вы опасаетесь, что не сможете при первом знакомстве с программой правильно перевести средства на мультисигнатурный адрес и боитесь их потерять — в этом случае не публикуйте Tx1 сразу, а сначала выпустите TxR и убедитесь в её корректности.
ВНИМАНИЕ: в связи со
свежевсплывшей уязвимостью bitcoin-протокола не гарантируется стопроцентная безопасность для покупателя последующих схем (с транзакцией возврата).
3. Покупка/обмен по предварительной договорённости без ожидания подтверждений и без доступа в интернет.
As1,...,Asn (start), Ap (participant), Af (final) — адреса покупателя, в частном случае могут быть одинаковыми; Bp, Bf — то же самое для продавца. TxR — reserve transaction, TxP — payment transaction, Tx1 — транзакция пополнения баланса.
Покупатель создаёт и подписывает транзакцию
Tx1: As1 & ... & Asn → {Ap,Bp}
но пока не публикует её. Также покупатель создаёт резервную транзакцию возврата
TxR: (id(Tx1),0){Ap,Bp} → Af; TxR.nlocktime = currtime + delay
(delay может быть равным, допустим, неделе)
Подписывает своим ключом транзакцию TxR (она подписывается лишь наполовину, нужна ещё подпись продавца). Передаёт TxR_part продавцу. Продавец проверяет TxR_part, доподписывает её и возвращает полностью подписанную TxR покупателю. Покупатель проверяет TxR и в случае её корректности публикует Tx1.
На данный момент ситуация такова, что покупатель свои средства не теряет — даже если продавец исчезнет, покупатель сможет получить свои деньги обратно после TxR.nlocktime.
Одновременно с подписью TxR_part продавец формирует транзакцию оплаты
TxP: (id(Tx1),0){Ap,Bp} → Bf
подписывает свою часть и передаёт TxP_part вместе с TxR покупателю. Покупатель проверяет TxP_part, доподписывает её своим ключом и, не публикуя TxP, едет за покупкой/обменом. В момент совершения сделки покупатель просто передаёт TxP продавцу. Продавец проверяет TxP и публикует её (ему необязательно публиковать её сразу, это лишь нужно сделать до TxR.nlocktime).
Double spend с адреса {Ap,Bp} (точнее, с (id(Tx1),0)) невозможен, т.к. для него требуется подпись ключами и продавца, и покупателя. Поэтому, а также из-за того, что TxR временно заблокирована, публикование TxP можно отложить, а ожидание подтверждений вообще отбросить. Теоретически возможен лишь double spend с адресов As1...Asn вместо транзакции Tx1, но предполагается, что от момента предварительной договорённости (включения Tx1 в блокчейн) до момента покупки прошло достаточно много подтверждений.
4. Модификация предыдущей схемы для множественных покупок/обмена по частям без отправки промежуточных транзакций в блокчейн.
{Ap,Bp} теперь рассматриваем как некий счёт покупателя в магазине (у продавца, в обменнике).
Точно так же генерируем, подписываем, обмениваемся и публикуем Tx1 и TxR, как в предыдущем варианте (только, возможно, стоит отодвинуть TxR.nlocktime на более дальний срок, особенно если планируется длительное сотрудничество). Но теперь продавец запрашивает трату лишь части средств покупателя транзакцией
TxP[1]: (id(Tx1),0){Ap,Bp} → (payment[1])Bf & (change[1])Af; TxP[1].nlocktime = TxR.nlocktime - delta[1]
Можно использовать, например, delta == 3 часа.
Продавец отправляет TxP[1]_part, покупатель получает её, проверяет, доподписывает и отправляет TxP[1] продавцу.
Для новых покупок/траншей:
TxP[i]: (id(Tx1),0){Ap,Bp} → (cumulated_payment[i])Bf & (change[i])Af; TxP[i].nlocktime = TxP[i-1].nlocktime - delta[i]
Аналогично для последующих. Обратите внимание, что ни одна из вышеперечисленных транзакций кроме Tx1 в блокчейне не публикуется.
На данном этапе средства обоих участников «виртуальны» (их ещё нельзя потратить ни продавцу, ни покупателю). Однако, если сейчас сотрудничество прекратится, то продавец опубликует TxP[last] в момент времени TxP[last].nlocktime, и каждый участник получит свою долю в единоличное распоряжение. Единственный момент — продавцу следует публиковать транзакцию TxP[last] сразу после наступления TxP[last].nlocktime, иначе через некоторое время у покупателя появится возможность опубликовать предыдущую транзакцию TxP[last-1] или даже TxP[last-k], которые отменят оплату k последних покупок.
В случае, если нужно снять средства, то очередную транзакцию оплаты TxP[ i ] выпускаем без nlocktime и публикуем её в блокчейне.
Для пополнения баланса можно просто перевести сумму пополнения на {Ap,Bp}
Tx2: An+1,...,An+m → {Ap,Bp}
Tx2 также стоит публиковать только после выпуска TxR2
TxR2: (id(Tx2),0){Ap,Bp} → Af; TxR2.nlocktime = TxR.nlocktime
Для последующих покупок:
TxP[i]: (id(Tx1),0){Ap,Bp} & (id(Tx2),0){Ap,Bp} → (cumulated_payment[i])Bf & (change[i])Af;
TxP[i].nlocktime = TxP[i-1].nlocktime - delta[i]
5. Модификация предыдущей схемы для случая, когда возможно движение средств в обе стороны.
- средства вносит один участник («покупатель»):
Действия те же, что и в предыдущей схеме, только подписывает TxP[ i ] первым тот, кто в данный момент собирается принимать биткоины. Ну и следить за приближением currtime к TxP[ i ].nlocktime теперь должны оба.
- средства вносят оба равноправных участника:
То же, что и в предыдущем варианте. Единственный нюанс — теперь возникает новая транзакция Tx2, переводящая средства от участника B на общий адрес. Для этой транзакции участником A (который на данной стадии играет роль продавца) подписывается транзакция возврата TxRB, TxRB.nlocktime = TxRA.nlocktime. Ну и теперь все TxP тратят средства с выходов как Tx1, так и Tx2 (аналогично варианту с пополнением баланса):
TxP[i]: (id(Tx1),0){Ap,Bp} & (id(Tx2),0){Ap,Bp} → (shareB[i])Bf & (shareA[i])Af;
TxP[i].nlocktime = TxP[i-1].nlocktime - delta[i]
Для гарантированного получения своих средств назад обоим участникам необходимо хранить лишь последнюю TxP, а также все TxR, выпущенные после последней TxP (после очередной TxP, включающей соответствующие входы, все TxR становятся неактуальными).
Предупреждение: для каждого совместного счёта следует использовать отдельный адрес-участник. Если используется один адрес (Bp), возможна такая ситуация:
- участник A говорит, что Ap принадлежит ему, генерирует и подписывает TxA, просит магазин подписать
TxRA_part: (id(TxA),0){Ap,Bp} → Af; TxRA.nlocktime = currtime + delay
и публикует TxA;
- участник E говорит, что Ep == Ap принадлежит ему, якобы генерирует и якобы подписывает TxE == TxA, просит магазин подписать
TxRE_part: (id(TxA),0){Ap,Bp} → Ef; TxRE.nlocktime произвольное
(желательно TxRE.nlocktime < TxRA.nlocktime, зависит от разрешения магазина выбирать delay самостоятельно), а затем получает средства после TxRE.nlocktime (если до этого момента в блокчейне не будет опубликована TxRA или TxP[ i ]).
Если же адреса BAp и BEp будут разными, то для кражи злоумышленнику придётся подбирать Eup такой, чтобы {Eup,BEp} == {Ap,BAp} (т.е. чтобы хэши их redeemScript'ов совпадали), что на данный момент практически нереально.
6. Модификация п.4 для множественных покупок/обмена с участием централизованного посредника.
C — адреса посредника.
Каждая из сторон (покупатели и продавцы) независимо друг от друга и в разное время заключают соглашения с посредником, перечисляют средства на совместные с ним адреса и генерируют транзакции возврата. Покупатель совершает покупку, продавец формирует транзакцию оплаты (перевод части средств с совместного с посредником счёта)
TxPB[i]: (id(Tx1B),0){Bp,CBp} → (cumulated_paymentB[i])Bf & (changeB[i])CBf;
TxPB[i].nlocktime = TxPB[i-1].nlocktime - deltaB[i]
подписывает её своим ключом и отправляет TxPB_part[ i ] посреднику, дополнительно указав, какому покупателю отправить счёт. Посредник принимает её, генерирует транзакцию оплаты для покупателя
TxPA[j]: (id(Tx1A),0){Ap,CAp} → (cumulated_paymentA[j])CAf & (changeA[j])Af;
TxPA[j].nlocktime = TxPA[j-1].nlocktime - deltaA[j]
подписывает её своим ключом и отправляет TxPA_part[j] покупателю. Вместе с этим посредник формирует документ, в котором указаны TxPB_part[ i ] и TxPA_part[j], подписывает его (например, с помощью PGP) и отправляет продавцу. Этот документ в дальнейшем будет являться доказательной базой, если посредник вздумает принять оплату от покупателя, но не вернуть эту оплату продавцу.
Покупатель проверяет TxPA_part[j] (в т.ч. её соответствие тому, что получил продавец в документе), доподписывает её и возвращает TxPA[j] посреднику. Посредник, проверив TxPA[j], доподписывает TxPB[ i ] и в свою очередь передаёт последнюю продавцу.
Риски, вносимые централизованным посредником:
- блокировка средств. Возможна лишь временная, т.к. у всех подписавших договор есть транзакции возврата.
- приём оплаты от покупателя (TxPA) и отсутствие передачи связанной TxPB продавцу. В этом случае покупатель передаёт полностью подписанную транзакцию TxPA продавцу, а тот выкладывает в общем доступе претензию (где указаны TxPA и подписанный документ с TxPB_part и TxPA_part) с требованием выпустить TxPB. В этой ситуации посредник либо уступает требованию, либо теряет репутацию, и клиенты переходят к другим посредникам. Если же сумма оплаты столь велика, что её потеря будет чувствительна для покупателя, то можно либо переводить её частями, либо перечислить напрямую от покупателя продавцу без посредников (необходимость ожидания подтверждений — меньшее зло в данном случае).
Пока всё.