比特币 - 运行 Tumbler

本文档介绍了 JoinMarket 的 Tumbler 工具,用于通过多次 CoinJoin 交易打破地址之间的关联,从而恢复隐私。文章详细介绍了 Tumbler 的工作原理、交易调度、日志记录以及如何解读控制台输出。同时,也讨论了调整交易计划和潜在的失败情况,并为用户提供了关于费用、资金准备和参数设置的建议。

请注意,tumbler 可以作为脚本运行:

(jmvenv)a@~/joinmarket-clientserver/scripts$ python tumbler.py --help

或者从 JoinmarketQt 应用程序的“多次合并”选项卡中运行(请参阅指南),

或者通过像 JAM 这样的 Web 应用程序使用 RPC-API。

目录

  1. Tumbler 简介

    a. 关于费用的说明

  2. 它是如何运作的 - 算法

    a. 示例 1

    b. 示例 2

  3. 计划表(交易列表)

  4. Tumbler 计划表和日志记录

  5. 解释关键控制台输出

  6. 调整计划表

  7. 重试发生的频率

  8. 可能的失败向量

<a name="introduction" />

Tumbler 简介

Tumbler 是一个 JoinMarket 机器人,它试图完全打破地址之间的联系。它用于恢复已被破坏的隐私。它创建了许多 coinjoin 来以不同的数量和时间来回传递币。这样做的目的是帮助人们维护他们的安全和尊严;这样做的理由与不直播你房子里每个房间的实时摄像头馈送的理由相同。

话虽如此,围绕如何使用此类工具来升级隐私有很多微妙之处——无论是 Joinmarket 总体上,还是此处介绍的“tumbler 算法”都不是万能的。考虑一下你是如何使用它的。

<a name="a-note-on-fees" />

关于费用的说明

由于 coinjoin 交易比“普通”比特币交易大,因此在高费用时期,矿工费可能会高达(或更高)0.002-0.004 BTC(根据 4kB 交易、50-100 sats/vbyte 估算)。因此,对于 10 笔交易,这是使用默认参数和三个目标地址时的实际数量,你最终可能仅在比特币交易费用上支付数十甚至数百 (!) 美元。与此相比,Coinjoin 费用很可能微不足道。

这 50 美元的总矿工费(示例数字)与你要 tumbling 的比特币数量无关,因此你必须考虑对于远小于 500 美元的金额(10% 的费用!)是否值得。请注意,你可以通过在 joinmarket.cfg 中设置字段 tx_fees 来支付较小的比特币矿工费(请参阅使用指南joinmarket.cfg 中的注释)。这当然会减慢速度 - 这可能不是一件坏事。

另一方面,对于更大的金额(价值约为 1000 美元以上),情况会发生显着变化,并且 coinjoin 费用往往会变得更加重要。但是,有足够的机器人具有固定大小的费用和超低的百分比费用,你可能会发现费用不是问题。在这种情况下,为整个运行支付低于 1% 的费用是正常的。

当然,以上情况在非常低的费用体系中并不适用,但“tumbler 代表大约 100 笔一进一出交易”的原则仍然适用。

TLDR:注意费用,尤其是在网络费用很高的情况下,在这种情况下,可能值得避免使用 tumbler。

<a name="algo" />

它是如何运作的 - 算法

基本概念:

首先,我们需要多个目标地址;默认值为 3,但你可以更高。为什么?因为如果整个金额最终都落在同一个地方(减去费用;这些费用通常很重要,但不足以打破联系),那么尝试通过一堆交易“混合”3.754 BTC 没有任何意义。

其次,我们需要添加随机延迟,以便在相当长的时间内分散这些交易。这并不是真正的可选;即使 Joinmarket 的交易量是今天的 10 倍,如果你在 5-10 个区块的时间内完成所有这些交易,它仍然会非常明显,并且像拇指酸痛一样突出。你希望这些交易是这段时间内一些 Joinmarket 交易,而不是全部!(如果 Joinmarket 每单位时间的交易量是 1000 倍,那么也许你可以快速完成此操作,但比特币甚至无法支持这一点!)。

所以现在,概述一下 tumbler 的工作原理。基本思想是将币从一个 混合深度(mixdepth) 移动到另一个,按顺序,但(通常)在多个交易中,并且始终完全清空每个 混合深度(mixdepth),最后(即使用“清扫”,没有剩余找零输出的 币合并(coinjoins))。理解此过程的最佳方法是通过示例。

<a name="example1" />

示例 1。 混合深度(mixdepth) 0 中的三个 utxo(每个 1BTC),4 个 混合深度(mixdepth),9 个交易对手,每个 混合深度(mixdepth) 3 笔交易,3 个目标地址 A、B、C。

这是最简单的设置,几乎与推荐的默认设置一样。请注意,这里我们特别指的是 混合深度(mixdepth) 1,2,3,4 刚开始时都是空的。

阶段 1:混合深度(mixdepth) 0 中的币将以清扫的方式移动到 混合深度(mixdepth) 1。没有资金滞后;费用的全部金额(假设为 2.99 BTC)将到达 混合深度(mixdepth) 1 中的“内部”地址。当然,关键是交易输出中将有 9 个完全相同的 2.99 BTC utxo;只有一个是你的。

阶段 2:

  • 现在将有 3 笔从 混合深度(mixdepth) 1 到 混合深度(mixdepth) 2 的交易。最后一笔将是清扫(也是到 混合深度(mixdepth) 2)。
  • 然后,从 混合深度(mixdepth) 2 进行 3 笔交易。前两笔将转到 混合深度(mixdepth) 3,最后一笔(清扫)将转到目标地址 A。
  • 然后,从 混合深度(mixdepth) 3 进行 3 笔交易。前两笔将转到 混合深度(mixdepth) 4,最后一笔(清扫)将转到目标地址 B。
  • 然后,从 混合深度(mixdepth) 4 进行一笔交易,到最终目标地址 C。

这是 Joinmarket 的代码生成的计划表示例(地址是测试网络):

0,0,9,INTERNAL,0.02,16,0
1,0.07158886670804065,9,INTERNAL,0.15,16,0
1,0.3104360747679161,9,INTERNAL,0.25,16,0
1,0,9,INTERNAL,0.41,16,0
2,0.28860335923421476,9,INTERNAL,0.31,16,0
2,0.17728531788154556,9,INTERNAL,0.04,16,0
2,0,9,mzzAYbtPpANxpNVGCVBAhZYzrxyZtoix7i,0.05,16,0
3,0.1593149311659825,9,INTERNAL,0.05,16,0
3,0.5469121480293317,9,INTERNAL,0.08,16,0
3,0,9,mifCWfmygxKhsP3qM3HZi3ZjBEJu7m39h8,0.04,16,0
4,0,9,mnTn9KVQQT9zy9R4E2ZGzWPK4EfcEcV9Y5,0.07,16,0

要理解这里的术语“计划”以及上述列表的含义,请参阅下面的计划

请注意关于计数的混淆点“混合深度(mixdepth) 4 的数量”这里意味着在阶段 2 中使用了 4 个 混合深度(mixdepth),因此我们从 1 开始到 4 结束。还要注意,最后一个 混合深度(mixdepth) 总是不同的,因为只有一次清扫到最终目标地址之一。

交易对手的数量:通过命令行上的 -N 控制,默认为 9 1,这意味着 9,标准偏差为 1(因此通常为 8-10);最好保持默认值,尽管你可以稍微降低一点,或者尝试显着提高(特别是使用 2022 年的新消息通道),如果如上所述的费用没有引起问题。

金额和时间:这些都是随机的。你无法使用该算法控制有多少资金流向不同的目标地址,并且每次交易之间的时间延迟也是随机的。有关如何控制平均时间的选项,请参阅 CLI 或 Qt 应用程序中的 tumbler“向导”。请注意,为了隐私,等待时间越长几乎总是越好。预计此过程将花费数小时或数天,这正是其预期用途。

<a name="example2" />

示例 2。 混合深度(mixdepth) 2 中的两个 utxo(每个 1BTC),混合深度(mixdepth) 4 中的一个 utxo,8 个 混合深度(mixdepth),9 个交易对手,每个 混合深度(mixdepth) 4 笔交易,4 个目标地址 A、B、C、D。

<a name="basic" />

首先,请注意,如果你要通过超过默认的 4 个 混合深度(mixdepth) 进行混合,则可以使用超过 3 个的目标地址(这样做是好事)。 其次,请注意,截至 此提交 的 tumbler 算法现在循环通过默认的 5 个 混合深度(mixdepth),而不是创建额外的 混合深度(mixdepth)。这意味着 混合深度(mixdepth) 路径如下:

阶段 1:

  • 混合深度(mixdepth) 2 清扫到 混合深度(mixdepth) 3
  • 混合深度(mixdepth) 4 清扫到 混合深度(mixdepth) 0

阶段 2: 起始 混合深度(mixdepth) 为 0,因为那是阶段 1 之后最低的非空 混合深度(mixdepth)。然后,序列为 (0->1, 1->2, 2->3, 3->4, 4->0, 0->1, 1->2)。最后一笔交易将从 混合深度(mixdepth) 2 清扫到最终目标地址。

多次使用相同的 混合深度(mixdepth) 不会“互相干扰”,原因有两个:一是 Joinmarket 永远不会重复使用地址,二是我们在遍历每个 混合深度(mixdepth) 时总是会清扫(因此完全清除)每个 混合深度(mixdepth)

这样做更简洁:即使我们想要运行非常大的 tumbler 算法,我们也会坚持钱包中固定数量的 混合深度(mixdepth)/帐户。

这是一个具有这些参数的测试示例计划:

4,0,9,INTERNAL,0.22,16,0
2,0,9,INTERNAL,1.25,16,0
0,0.1287547602736554,9,INTERNAL,0.34,16,0
0,0.33777065308789445,9,INTERNAL,0.12,16,0
0,0.2416658618765749,9,INTERNAL,0.05,16,0
0,0,9,INTERNAL,0.23,16,0
1,0.4248409290648639,9,INTERNAL,0.01,16,0
1,0.33866158339454555,9,INTERNAL,0.02,4,0
1,0.010807366510609207,9,INTERNAL,0.13,16,0
1,0,9,INTERNAL,0.11,16,0
2,0.04086022411519208,9,INTERNAL,0.82,16,0
2,0.20924362829352816,9,INTERNAL,0.03,16,0
2,0.03518603894933314,9,INTERNAL,0.05,16,0
2,0,9,INTERNAL,0.16,16,0
3,0.13973910506875786,9,INTERNAL,0.38,4,0
3,0.21418596171826687,9,INTERNAL,0.24,16,0
3,0.3792667736100306,9,INTERNAL,0.08,16,0
3,0,9,INTERNAL,0.07,16,0
4,0.23084503924196553,9,INTERNAL,0.02,16,0
4,0.3566850751084202,9,INTERNAL,0.07,16,0
4,0.06412832650536227,9,INTERNAL,0.09,16,0
4,0,9,mzzAYbtPpANxpNVGCVBAhZYzrxyZtoix7i,0.04,16,0
0,0.3794032390530363,9,INTERNAL,0.02,16,0
0,0.10756327418131051,9,INTERNAL,0.93,16,0
0,0.40107055434802497,9,INTERNAL,0.07,16,0
0,0,9,mifCWfmygxKhsP3qM3HZi3ZjBEJu7m39h8,0.11,16,0
1,0.05776628660005234,9,INTERNAL,0.93,16,0
1,0.1936955942281181,9,INTERNAL,0.66,16,0
1,0.13956928336353558,9,INTERNAL,0.14,16,0
1,0,9,bcrt1qcnv26w889eum5sekz5h8we45rxnr4sj5k08phv,0.58,16,0
2,0,9,mnTn9KVQQT9zy9R4E2ZGzWPK4EfcEcV9Y5,0.52,16,0

重新启动

甚至在讨论实际的代码级操作之前,我们可以看到:这种方法允许我们在启动时在任何 混合深度(mixdepth) 中都有币;因此,如果我们手动结束了运行一半,或者如果交易反复失败并且你不得不放弃,那么我们就不再有“重新启动”的概念了。你可以自行判断;如果你启动了一个 8 个 混合深度(mixdepth) 的 tumbler 运行,并且在 3 个 混合深度(mixdepth) 后停止了,你可以稍后运行另一个 5 个 混合深度(mixdepth),如果你愿意的话。对于目标地址,你无论如何都无法控制到达不同目标的比率(从技术上讲是可能的,但不建议这样做,你需要手动创建计划表并仔细考虑),因此这实际上并没有改变这方面。

无论如何,停止并重新启动来延迟整个过程是相当明智的;如上所述,我们希望这个过程缓慢,而不是快速。

关于承诺的提醒。

按照使用指南了解如何为你的钱包充值。不要忘记阅读页面,否则你可能会遇到问题。

对于 Tumbler 来说,这实际上是一个非常重要的领域,因为我们经常使用清扫。在一开始使用 3 个 utxo 进行充值并不是非常关键,但无论如何都要尝试使用 2 个 utxo 进行充值。而且:

强烈建议使用 8 个或更高的交易对手计数(如上所述;命令行上的 -N --minmakercount 为 4(默认值)或 5,以便最大程度地实现每次发出请求时都能成功加入(如果在协商的第一阶段 maker 不稳定,只要最多 --minmakercount 响应正确,你仍然可以完成)。

<a name="schedules" />

计划表(交易列表)

在此实现中,每个 币合并(coinjoin) 都有一个关联的“计划表”,格式如下:

[混合深度(mixdepth), 金额-分数, N-交易对手(请求的), 目标地址, 等待时间(分钟), 舍入, 指示未完成/广播/已完成的标志 (0/txid/1)]

[] 这里表示 Python 列表。它以 csv 格式记录在文件中(因为在某些情况下用户可能会编辑)。请参阅 repo 中给出的测试网示例。关于格式的几个额外说明:

  • 第 4 个条目,目标地址,可以具有特殊值“INTERNAL”和“addrask”;前者表示币将发送到“下一个”混合深度(mixdepth),以最大 混合深度(mixdepth) 为模。后者从用户提供的目标中获取一个目标,无论是在初始命令行中还是在运行期间的提示中。

  • 第二个条目,金额分数,是一个介于 0 和 1 之间的十进制数;这是 Tumbler 特有的;如果计划表有一个(非零)整数,则该整数用于(在 sendpayment 中)非 Tumbler 币合并(coinjoin) 发送。

  • 第二个条目的 0 金额表示,与命令行标志一样,表示清扫;小数表示 混合深度(mixdepth) 分数(对于 Tumbler),例如,如果你的 混合深度(mixdepth) 的总余额为 10.0 BTC,并且该值为 0.22,则将发送 2.2 BTC。

  • 第 6 个条目 rounding 是将 币合并(coinjoin) 金额舍入到多少个有效数字。例如,舍入值为 2 表示 0.12498733 将舍入为 0.1200000。舍入值 16 表示不舍入。清扫 币合并(coinjoin) 金额永远不会舍入。

对于 sendpayment.py 脚本,此计划表确实可以简单地写入文件中并作为参数传递(因此,Tumbler 和 sendpayment 脚本将来可能会合并)。

正如你可以想象的那样,tumbler.py 脚本和 JoinmarketQt 中的 MultiJoin 向导的想法很简单,根据 此 PR代码)中介绍的算法,生成一个 tumbler 计划表,但是它被持久化了 - 请参阅下一节。

<a name="logging" />

Tumbler 计划表和日志记录

有两个日志文件可以帮助跟踪 Tumbler 的进度。第一个文件默认为 &lt;datadir>/logs/TUMBLE.schedule,但可以使用新的 --schedulefile 选项更改其名称。在此文件中,根据用户命令行选项(例如 -N 表示交易对手,-M 表示 混合深度(mixdepth) 等)在启动时生成的计划表将被记录下来,并且在每次在网络上看到交易时都会更新 - 特别是更新的是上面提到的“已完成”标志,以及用户目标的目标地址(替换为“addrask”)。因此,通过随时打开它,你可以看到当前状态的简要视图(特别注意最后一个条目中的“1”或“0”;“1”表示交易已完成)。

然而,另一个文件更专门用于帮助跟踪:目前硬编码为 &lt;datadir>/logs/TUMBLE.log,它将显示:交易时间、txid、目标地址,以及任何失败和重试的实例。它是一个标准的日志文件,默认情况下为多次运行进行追加操作)。

<a name="interpreting" />

解释关键控制台输出

你将定期看到以下消息之一:

时间戳 [MainThread  ] [INFO ]  STALL MONITOR:
时间戳 [MainThread  ] [INFO ]  未检测到停止,继续
时间戳 [MainThread  ] [INFO ]  STALL MONITOR:
时间戳 [MainThread  ] [INFO ]  Tx 已经被推送;忽略

这两者都表示程序识别到之前的交易(不一定是正在进行的交易)没有出现任何问题,并且可以随时发生;这些意味着交易已成功处理,可以忽略。如果你看到这个:

时间戳 [MainThread  ] [INFO ]  STALL MONITOR:
时间戳 [MainThread  ] [INFO ]  检测到停止。正在重新生成交易并重试。

这意味着当前交易由于某种原因失败,你稍后会看到一条消息指示失败的计划条目的参数,然后将对其进行调整并重试。请参阅下面的调整关于“调整”。

你有时在控制台中看到的另一个重要输出是与承诺源查找失败的情况下打印到 commitments_debug.txt 的相同信息,例如:

1:通过年龄和大小限制,但已被使用太多次的 Utxo(请参阅配置中的 taker_utxo_retries):
None
2:确认少于 5 次的 Utxo:
3a001fa0272df5c43c2c38d91d1f784b4ba18c18043355b88c7c713dd3ecc78c:5
...

如果在之后 tumbler 继续运行(关于如果它不运行,请参阅下面的关于失败/崩溃向量的部分下面),你无需执行任何操作;通常,过一段时间后你会看到“正在重新生成交易”消息,并且它会再次尝试,直到 (a) utxo 足够旧(5 次确认),或者 (b) 在极少数情况下,你将不得不等到金额正确(20% 规则),这取决于“调整”,请参阅下一部分。

制造商没有回应

当过多的异常制造商没有完成协议时,就会发生这种情况。如上所述,只需等待发生调整后重新生成。

<a name="tweaking" />

调整计划表

如果单个交易失败,tumbler 将积极尝试继续。这与原始实现中发生的情况类似,但也略有不同。在出现像上面这样的“检测到停止”消息后,将按以下两种方式之一调整当前计划条目

  • 对于非清扫,金额分数(在计划表中记录为第二个条目,一个小数)将被更改,以及该 混合深度(mixdepth) 中的所有后续金额分数,以保持原始计划表的总体分布的方式完成。但是,N(交易对手的数量)不会更改,请记住,如果未收到响应,我们会利用回退到 minimum_makers,因此更高的 N 始终对可靠性更好。调整金额分数可以通过更改你的 tumbler 感知的流动性来帮助,但有时也可以通过更改哪些 PoDLE 承诺有效(请记住 20% 规则)来帮助。

  • 对于清扫,金额无法更改,但另一方面,我们可以通过减少 N(对于清扫,不可能回退)来提高成功率。

重复进行此调整过程,直到交易完成为止(如有必要)。可能需要多次重复的一种情况:如果你设置较低的 -l 值(时间等待参数),你可能经常没有足够老的任何 PoDLE 承诺,因此必须等待 5 次确认;在这种情况下,它只会不断重试,直到情况属实。(注意!太年轻的 Utxo 承诺不会被用完;你自己的机器人会识别出这一点,并且不会在它们有效之前广播它们)。

<a name="how-often-do-retries-occur" />

重试发生的频率?

目前硬编码为 20 * maker_timeout_sec,硬编码数字 20 是因为我不想要另一个配置变量,尽管当然可以这样做。这是 停止监视器(stall monitor) 在客户端协议中唤醒的速率,该设置在代码中的此处。请注意,默认情况下,这相当慢,为 10 分钟。

<a name="failure-vectors" />

可能的失败向量 - 崩溃或关闭

  • 未能找到承诺 - 如果没有未使用的 PoDLE 承诺可用,即使进行调整,此条件也不会更改,因此脚本将终止。这可以更改为允许动态更新 commitments.json 文件(添加外部 utxo),但我认为现在这不是正确的选择。另一方面,正如上面所指出的,如果承诺只是太年轻,脚本将不断调整和重试。我建议在运行前使用 add-utxo.py 脚本准备外部承诺以提高稳健性,尽管对于成功来说这不是必需的。
  • 网络错误 - 这不应引起问题。Joinmarket 非常稳健地处理对其 Onion 服务和/或 IRC 服务器的网络中断。
  • 流动性不足。这是一个棘手的问题 - 特别是对于清扫,如果潜在交易对手的数量很少,并且如果其中一些人故意不响应,则你可能会用完交易对手。目前,脚本只会无限期地重试。

请注意,各种其他失败向量实际上不会引起问题,例如臭名昭著的“txn-mempool-conflict”;调整可以处理这些情况。

  • 原文链接: github.com/JoinMarket-Or...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
JoinMarket-Org
JoinMarket-Org
江湖只有他的大名,没有他的介绍。